diff options
author | Sarah Chin <sarahchin@google.com> | 2022-07-01 23:15:33 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-07-01 23:15:33 +0000 |
commit | 34d8acbfb0b7a3765b0bda11e05028ee666a4cda (patch) | |
tree | eef029cd35865af2f596e4ad49ceee42699bc2c7 | |
parent | fec1b69a236e5c5850b9a57d96ec755c7800f8a9 (diff) | |
parent | 9b9286746ec909e7507600c5bb24e495ae88ce74 (diff) | |
download | telephony-34d8acbfb0b7a3765b0bda11e05028ee666a4cda.tar.gz |
Fix APM race conditions in ServiceStateTracker am: 9b9286746e
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/opt/telephony/+/19121301
Change-Id: I52335ca8233715fa3f7dec5a67991b4bd2a0276d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rwxr-xr-x | src/java/com/android/internal/telephony/ServiceStateTracker.java | 36 | ||||
-rw-r--r-- | tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java | 60 |
2 files changed, 85 insertions, 11 deletions
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 751d59a623..3cba6acb77 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -1086,7 +1086,7 @@ public class ServiceStateTracker extends Handler { /** * Turn on or off radio power with option to specify whether it's for emergency call and specify * a reason for setting the power state. - * More details check {@link PhoneInternalInterface#setRadioPower( + * More details check {@link PhoneInternalInterface#setRadioPowerForReason( * boolean, boolean, boolean, boolean, int)}. */ public void setRadioPowerForReason(boolean power, boolean forEmergencyCall, @@ -1188,10 +1188,10 @@ public class ServiceStateTracker extends Handler { if (VDBG) log("received event " + msg.what); switch (msg.what) { case EVENT_SET_RADIO_POWER_OFF: - synchronized(this) { + synchronized (this) { if (mPhone.isUsingNewDataStack()) { - mPendingRadioPowerOffAfterDataOff = false; log("Wait for all data networks torn down timed out. Power off now."); + cancelPendingRadioPowerOff(); hangupAndPowerOff(); return; } @@ -1491,17 +1491,18 @@ public class ServiceStateTracker extends Handler { case EVENT_ALL_DATA_DISCONNECTED: if (mPhone.isUsingNewDataStack()) { log("EVENT_ALL_DATA_DISCONNECTED"); - if (mPendingRadioPowerOffAfterDataOff) { - mPendingRadioPowerOffAfterDataOff = false; - removeMessages(EVENT_SET_RADIO_POWER_OFF); - if (DBG) log("EVENT_ALL_DATA_DISCONNECTED, turn radio off now."); - hangupAndPowerOff(); + synchronized (this) { + if (mPendingRadioPowerOffAfterDataOff) { + if (DBG) log("EVENT_ALL_DATA_DISCONNECTED, turn radio off now."); + cancelPendingRadioPowerOff(); + hangupAndPowerOff(); + } } return; } int dds = SubscriptionManager.getDefaultDataSubscriptionId(); ProxyController.getInstance().unregisterForAllDataDisconnected(dds, this); - synchronized(this) { + synchronized (this) { if (mPendingRadioPowerOffAfterDataOff) { if (DBG) log("EVENT_ALL_DATA_DISCONNECTED, turn radio off now."); hangupAndPowerOff(); @@ -3132,12 +3133,12 @@ public class ServiceStateTracker extends Handler { && getRadioPowerOffDelayTimeoutForImsRegistration() > 0) { if (DBG) log("setPowerStateToDesired: delaying power off until IMS dereg."); startDelayRadioOffWaitingForImsDeregTimeout(); - // Return early here as we do not want to hit the cancel timeout code below. - return; } else { if (DBG) log("setPowerStateToDesired: powerOffRadioSafely()"); powerOffRadioSafely(); } + // Return early here as we do not want to hit the cancel timeout code below. + return; } else if (mDeviceShuttingDown && (mCi.getRadioState() != TelephonyManager.RADIO_POWER_UNAVAILABLE)) { // !mDesiredPowerState condition above will happen first if the radio is on, so we will @@ -3147,6 +3148,19 @@ public class ServiceStateTracker extends Handler { } // Cancel any pending timeouts because the state has been re-evaluated. cancelDelayRadioOffWaitingForImsDeregTimeout(); + cancelPendingRadioPowerOff(); + } + + /** + * Cancel the pending radio power off request that was sent to force the radio to power off + * if waiting for all data to disconnect times out. + */ + private synchronized void cancelPendingRadioPowerOff() { + if (mPhone.isUsingNewDataStack() && mPendingRadioPowerOffAfterDataOff) { + if (DBG) log("cancelPendingRadioPowerOff: cancelling."); + mPendingRadioPowerOffAfterDataOff = false; + removeMessages(EVENT_SET_RADIO_POWER_OFF); + } } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 7d9891d374..ff3e8b8990 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -92,6 +92,7 @@ import androidx.test.filters.FlakyTest; import com.android.internal.R; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; +import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.test.SimulatedCommands; import com.android.internal.telephony.uicc.IccCardApplicationStatus; @@ -380,6 +381,65 @@ public class ServiceStateTrackerTest extends TelephonyTest { } @Test + public void testSetRadioPowerWaitForAllDataDisconnected() { + // Start with radio on + sst.setRadioPower(true); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + + // Ensure data is connected + ArgumentCaptor<DataNetworkController.DataNetworkControllerCallback> callback = + ArgumentCaptor.forClass(DataNetworkController.DataNetworkControllerCallback.class); + verify(mDataNetworkController, times(1)).registerDataNetworkControllerCallback( + callback.capture()); + callback.getValue().onAnyDataNetworkExistingChanged(true); + + // Turn on APM and verify that SST is waiting for all data disconnected + sst.setRadioPower(false); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + verify(mDataNetworkController).tearDownAllDataNetworks( + eq(3 /* TEAR_DOWN_REASON_AIRPLANE_MODE_ON */)); + assertTrue(sst.hasMessages(38 /* EVENT_SET_RADIO_POWER_OFF */)); + + // Data disconnected, radio should power off now + callback.getValue().onAnyDataNetworkExistingChanged(false); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); + } + + @Test + public void testSetRadioPowerCancelWaitForAllDataDisconnected() { + // Start with radio on + sst.setRadioPower(true); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + + // Ensure data is connected + ArgumentCaptor<DataNetworkController.DataNetworkControllerCallback> callback = + ArgumentCaptor.forClass(DataNetworkController.DataNetworkControllerCallback.class); + verify(mDataNetworkController, times(1)).registerDataNetworkControllerCallback( + callback.capture()); + callback.getValue().onAnyDataNetworkExistingChanged(true); + + // Turn on APM and verify that SST is waiting for all data disconnected + sst.setRadioPower(false); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + verify(mDataNetworkController).tearDownAllDataNetworks( + eq(3 /* TEAR_DOWN_REASON_AIRPLANE_MODE_ON */)); + assertTrue(sst.hasMessages(38 /* EVENT_SET_RADIO_POWER_OFF */)); + + // Turn off APM while waiting for data to disconnect + sst.setRadioPower(true); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + + // Check that radio is on and pending power off messages were cleared + assertFalse(sst.hasMessages(38 /* EVENT_SET_RADIO_POWER_OFF */)); + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + } + + @Test @SmallTest public void testSetRadioPowerOnForEmergencyCall() { // Turn off radio first. |