diff options
-rw-r--r-- | service/java/com/android/server/wifi/SarInfo.java | 194 | ||||
-rw-r--r-- | tests/wifitests/src/com/android/server/wifi/SarInfoTest.java | 287 |
2 files changed, 481 insertions, 0 deletions
diff --git a/service/java/com/android/server/wifi/SarInfo.java b/service/java/com/android/server/wifi/SarInfo.java new file mode 100644 index 000000000..6eb777c65 --- /dev/null +++ b/service/java/com/android/server/wifi/SarInfo.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** + * This class represents the list of SAR inputs that will be used to select the proper + * power profile. + * This includes: + * - SAR body sensor status + * - Is there an ongoing voice call + * - Is SoftAP active + * It also contains info about state of the other Wifi modes + * - Client mode (Sta) + * - ScanOnly mode + * It also keeps history for the reporting of SAR states/scenario to avoid unnecessary reporting + * - keeps track of the last reported states + * - keeps track of the last reported SAR scenario + * - keeps track of if all wifi modes were disabled (no reporting should happen then) + */ +public class SarInfo { + /** + * This value is used as an initial value for the last reported scenario + * It is intended to be different than all valid SAR scenario values (including the + * reset value). + * Using this to initialize the lastReportedScenario results in that the first scenario + * (including reset) would be reported. + */ + public static final int INITIAL_SAR_SCENARIO = -2; + + /** + * This value is used for the reset scenario (no TX Power backoff) + * Valid scenario values only include scenarios with Tx Power backoff, + * so we need this one to represent the "No backoff" case. + */ + public static final int RESET_SAR_SCENARIO = -1; + + private static final String SAR_SENSOR_FREE_SPACE_STR = "SAR_SENSOR_FREE_SPACE"; + private static final String SAR_SENSOR_NEAR_BODY_STR = "SAR_SENSOR_NEAR_BODY"; + private static final String SAR_SENSOR_NEAR_HAND_STR = "SAR_SENSOR_NEAR_HAND"; + private static final String SAR_SENSOR_NEAR_HEAD_STR = "SAR_SENSOR_NEAR_HEAD"; + + public static final int SAR_SENSOR_FREE_SPACE = 1; + public static final int SAR_SENSOR_NEAR_HAND = 2; + public static final int SAR_SENSOR_NEAR_HEAD = 3; + public static final int SAR_SENSOR_NEAR_BODY = 4; + + /* For Logging */ + private static final String TAG = "WifiSarInfo"; + + public boolean mSarSensorEnabled; + + public int mSensorState = SAR_SENSOR_FREE_SPACE; + public boolean mIsWifiClientEnabled = false; + public boolean mIsWifiSapEnabled = false; + public boolean mIsWifiScanOnlyEnabled = false; + public boolean mIsVoiceCall = false; + public int mAttemptedSarScenario = RESET_SAR_SCENARIO; + + private boolean mAllWifiDisabled = true; + + /* Variables representing the last successfully reported values to hal */ + private int mLastReportedSensorState = SAR_SENSOR_FREE_SPACE; + private boolean mLastReportedIsWifiSapEnabled = false; + private boolean mLastReportedIsVoiceCall = false; + private int mLastReportedScenario = INITIAL_SAR_SCENARIO; + + SarInfo(boolean sarSensorEnabled) { + mSarSensorEnabled = sarSensorEnabled; + } + + /** + * shouldReport() + * This method returns false in the following cases: + * 1. If all Wifi modes are disabled. + * 2. Values contributing to the SAR scenario selection have not changed + * since last successful reporting. + * + * Special cases to allow for devices that require setting the SAR scenario value + * when the chip comes up (initial startup, or during operation) + * 1. This method would report true even with unchanged values from last reporting, + * if any wifi mode is just enabled after all wifi modes were disabled. + * 2. This method would report true the first time it is called with any wifi mode enabled. + */ + public boolean shouldReport() { + /* Check if all Wifi modes are disabled */ + if (!mIsWifiClientEnabled && !mIsWifiSapEnabled && !mIsWifiScanOnlyEnabled) { + mAllWifiDisabled = true; + return false; + } + + /* Check if Wifi was all disabled before this call */ + if (mAllWifiDisabled) { + return true; + } + + /* Check if some change happened since last successful reporting */ + if ((mSensorState != mLastReportedSensorState) + || (mIsWifiSapEnabled != mLastReportedIsWifiSapEnabled) + || (mIsVoiceCall != mLastReportedIsVoiceCall)) { + return true; + } else { + return false; + } + } + + /** + * reportingSuccessful() + * This method is called when reporting SAR scenario is fully successful + * This results in caching the last reported inputs for future comparison. + */ + public void reportingSuccessful() { + mLastReportedSensorState = mSensorState; + mLastReportedIsWifiSapEnabled = mIsWifiSapEnabled; + mLastReportedIsVoiceCall = mIsVoiceCall; + mLastReportedScenario = mAttemptedSarScenario; + + mAllWifiDisabled = false; + } + + /** + * resetSarScenarioNeeded() + * Returns true if a call towards HAL to reset SAR scenario would be necessary. + * Returns false if the last call to HAL was already a reset, and hence + * another call to reset the SAR scenario would be redundant. + */ + public boolean resetSarScenarioNeeded() { + return setSarScenarioNeeded(RESET_SAR_SCENARIO); + } + + /** + * setSarScenarioNeeded() + * Returns true if a call towards HAL to set SAR scenario to that value would be + * necessary. + * Returns false if the last call to HAL was to set the scenario to that value, hence, + * another call to set the SAR scenario to the same value would be redundant. + */ + public boolean setSarScenarioNeeded(int scenario) { + mAttemptedSarScenario = scenario; + return (mLastReportedScenario != scenario); + } + + /** + * dump() + * Dumps the state of SarInfo + */ + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("*** WiFi SAR Info Dump ***"); + pw.println("Current values:"); + pw.println(" Sensor state is: " + sensorStateToString(mSensorState)); + pw.println(" Voice Call state is: " + mIsVoiceCall); + pw.println(" Wifi Client state is: " + mIsWifiClientEnabled); + pw.println(" Wifi Soft AP state is: " + mIsWifiSapEnabled); + pw.println(" Wifi ScanOnly state is: " + mIsWifiScanOnlyEnabled); + pw.println("Last reported values:"); + pw.println(" Sensor state is: " + sensorStateToString(mLastReportedSensorState)); + pw.println(" Soft AP state is: " + mLastReportedIsWifiSapEnabled); + pw.println(" Voice Call state is: " + mLastReportedIsVoiceCall); + } + + /** + * Convert SAR sensor state to string + */ + public static String sensorStateToString(int sensorState) { + switch(sensorState) { + case SAR_SENSOR_FREE_SPACE: + return SAR_SENSOR_FREE_SPACE_STR; + case SAR_SENSOR_NEAR_BODY: + return SAR_SENSOR_NEAR_BODY_STR; + case SAR_SENSOR_NEAR_HAND: + return SAR_SENSOR_NEAR_HAND_STR; + case SAR_SENSOR_NEAR_HEAD: + return SAR_SENSOR_NEAR_HEAD_STR; + default: + return "Invalid SAR sensor state"; + } + } +} diff --git a/tests/wifitests/src/com/android/server/wifi/SarInfoTest.java b/tests/wifitests/src/com/android/server/wifi/SarInfoTest.java new file mode 100644 index 000000000..1f0e44c8a --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/SarInfoTest.java @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.support.test.filters.SmallTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * unit tests for {@link com.android.server.wifi.SarInfo}. + */ +@SmallTest +public class SarInfoTest { + private static final String TAG = "WifiSarInfoTest"; + + private SarInfo mSarInfo; + + private static final int SAR_SCENARIO_1 = 1; + private static final int SAR_SCENARIO_2 = 2; + + @Before + public void setUp() throws Exception { + mSarInfo = new SarInfo(true); + } + + @After + public void cleanUp() throws Exception { + } + + /** + * Test that at start, resetSarScenarioNeeded returns true, + * to allow for initial setting of normal scenario. + */ + @Test + public void testSarInfo_resetSarScenarioNeed_atStart() throws Exception { + assertTrue(mSarInfo.resetSarScenarioNeeded()); + } + + /** + * Test that at start, setSarScenarioNeeded returns true. + */ + @Test + public void testSarInfo_setSarScenarioNeeded_atStart() throws Exception { + assertTrue(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_1)); + } + + /** + * Test performing two successive reset of SAR scenario. + * The first should succeed, while the second should fail, since it is redundant. + */ + @Test + public void testSarInfo_repeat_reset_scenario() throws Exception { + /* Initial reset is allowed */ + assertTrue(mSarInfo.resetSarScenarioNeeded()); + mSarInfo.reportingSuccessful(); + + /* Now resetting again should not be allowed */ + assertFalse(mSarInfo.resetSarScenarioNeeded()); + } + + /** + * Test performing set SAR scenario after reset. + * The two attempts should succeed. + */ + @Test + public void testSarInfo_set_after_reset_scenario() throws Exception { + assertTrue(mSarInfo.resetSarScenarioNeeded()); + mSarInfo.reportingSuccessful(); + + /* Setting scenario should be allowed, since last call was for a reset */ + assertTrue(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_1)); + } + + /** + * Test performing setting SAR scenario twice with same value. + * The second attempt should fail. + */ + @Test + public void testSarInfo_set_twice_same_value_scenario() throws Exception { + assertTrue(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_1)); + mSarInfo.reportingSuccessful(); + + /* Second attempt should fail */ + assertFalse(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_1)); + } + + /** + * Test performing setting SAR scenario twice with different values. + * Both attempts should succeed. + */ + @Test + public void testSarInfo_set_twice_different_values_scenario() throws Exception { + assertTrue(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_1)); + mSarInfo.reportingSuccessful(); + + /* Setting scenario should be allowed */ + assertTrue(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_2)); + } + + /** + * Test performing reset of SAR scenario after setting it. + * Both attempts should succeed. + */ + @Test + public void testSarInfo_reset_after_set_scenario() throws Exception { + assertTrue(mSarInfo.setSarScenarioNeeded(SAR_SCENARIO_1)); + mSarInfo.reportingSuccessful(); + + /* Resetting scenario should be allowed */ + assertTrue(mSarInfo.resetSarScenarioNeeded()); + } + + /** + * Test that at start, shouldReport returns false (wifi modes still disabled). + */ + @Test + public void testSarInfo_shouldReport_all_wifi_disabled() throws Exception { + assertFalse(mSarInfo.shouldReport()); + } + + /** + * Test that once Wifi (any mode) is enabled, shouldReport returns true. + */ + @Test + public void testSarInfo_shouldReport_wifi_enabled() throws Exception { + mSarInfo.mIsWifiClientEnabled = true; + assertTrue(mSarInfo.shouldReport()); + } + + /** + * Test that setting sensor (with wifi disabled), shouldReport returns false. + */ + @Test + public void testSarInfo_check_sensor_wifi_disabled() throws Exception { + mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + assertFalse(mSarInfo.shouldReport()); + } + + /** + * Test that setting sensor (with some wifi mode enabled), shouldReport returns true. + */ + @Test + public void testSarInfo_check_sensor_wifi_enabled() throws Exception { + mSarInfo.mIsWifiSapEnabled = true; + assertTrue(mSarInfo.shouldReport()); + mSarInfo.reportingSuccessful(); + + mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + assertTrue(mSarInfo.shouldReport()); + } + + /** + * Test that setting sensor (with some wifi mode enabled), shouldReport returns true + * only the first time, following attempts should return false (since sensor state + * did not change) + */ + @Test + public void testSarInfo_check_sensor_multiple_wifi_enabled() throws Exception { + mSarInfo.mIsWifiScanOnlyEnabled = true; + mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + assertTrue(mSarInfo.shouldReport()); + mSarInfo.reportingSuccessful(); + + assertFalse(mSarInfo.shouldReport()); + } + + /** + * Test that setting sensor with different values (with wifi enabled), + * shouldReport returns true every time. + */ + @Test + public void testSarInfo_check_sensor_multiple_values_wifi_enabled() throws Exception { + mSarInfo.mIsWifiClientEnabled = true; + mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + assertTrue(mSarInfo.shouldReport()); + mSarInfo.reportingSuccessful(); + + mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_BODY; + assertTrue(mSarInfo.shouldReport()); + mSarInfo.reportingSuccessful(); + + mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + assertTrue(mSarInfo.shouldReport()); + } + + /** + * Test setting sensor while wifi is disabled, then enable wifi. + */ + @Test + public void testSarInfo_change_sensors_while_wifi_disabled() throws Exception { + mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + assertFalse(mSarInfo.shouldReport()); + + mSarInfo.mIsWifiClientEnabled = true; + assertTrue(mSarInfo.shouldReport()); + mSarInfo.reportingSuccessful(); + } + + /** + * Test having a voice call, shouldReport should return true + * Note: will need to report once before starting the call to remove + * the effect of sensor state change. + */ + @Test + public void testSarInfo_voice_call_wifi_enabled() throws Exception { + mSarInfo.mIsWifiClientEnabled = true; + assertTrue(mSarInfo.shouldReport()); + mSarInfo.reportingSuccessful(); + + mSarInfo.mIsVoiceCall = true; + assertTrue(mSarInfo.shouldReport()); + } + + /** + * Test starting SAP, shouldReport should return true + * Note: will need to report once before starting SAP to remove + * the effect of sensor state change. + */ + @Test + public void testSarInfo_sap_wifi_enabled() throws Exception { + mSarInfo.mIsWifiClientEnabled = true; + assertTrue(mSarInfo.shouldReport()); + mSarInfo.reportingSuccessful(); + + mSarInfo.mIsWifiSapEnabled = true; + assertTrue(mSarInfo.shouldReport()); + } + + /** + * Test that setting sensor (with wifi enabled), reporting not successful + * Then, we should expect that shouldReport returns true evne if we have + * no further changes until reporting is successful. + */ + @Test + public void testSarInfo_check_sensor_reporting_no_success_reporting() throws Exception { + mSarInfo.mIsWifiClientEnabled = true; + mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + assertTrue(mSarInfo.shouldReport()); + + /* No call to reportingSuccessful() will be done */ + assertTrue(mSarInfo.shouldReport()); + + /* Now call reportingSuccessful() */ + mSarInfo.reportingSuccessful(); + assertFalse(mSarInfo.shouldReport()); + } + + /** + * Test that setting sensor (with wifi enabled), reporting successful + * Then, changing the sensor state with no successful reporting. + * Followed by reverting to the previous state. + */ + @Test + public void testSarInfo_check_sensor_reporting_no_success_reporting_revert() throws Exception { + mSarInfo.mIsWifiClientEnabled = true; + mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + assertTrue(mSarInfo.shouldReport()); + mSarInfo.reportingSuccessful(); + + /* Changing the sensor state and fail to report */ + mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_BODY; + assertTrue(mSarInfo.shouldReport()); + + /* Changing the sensor back to the same value as last reported */ + mSarInfo.mSensorState = SarInfo.SAR_SENSOR_NEAR_HEAD; + assertFalse(mSarInfo.shouldReport()); + } +} |