Loading src/java/com/android/internal/telephony/ServiceStateTracker.java +74 −66 Original line number Diff line number Diff line Loading @@ -25,10 +25,8 @@ import static com.android.internal.telephony.uicc.IccRecords.CARRIER_NAME_DISPLA import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ContentResolver; Loading Loading @@ -251,6 +249,12 @@ public class ServiceStateTracker extends Handler { /** Signal strength poll rate. */ private static final int POLL_PERIOD_MILLIS = 20 * 1000; /** * The time we wait for IMS to deregister before executing a pending radio power off request. */ @VisibleForTesting public static final int DELAY_RADIO_OFF_FOR_IMS_DEREG_TIMEOUT = 3 * 1000; /** Waiting period before recheck gprs and voice registration. */ public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; Loading Loading @@ -290,6 +294,7 @@ public class ServiceStateTracker extends Handler { public static final int EVENT_ICC_CHANGED = 42; protected static final int EVENT_GET_CELL_INFO_LIST = 43; protected static final int EVENT_UNSOL_CELL_INFO_LIST = 44; // Only sent if the IMS state is moving from true -> false protected static final int EVENT_CHANGE_IMS_STATE = 45; protected static final int EVENT_IMS_STATE_CHANGED = 46; protected static final int EVENT_IMS_STATE_DONE = 47; Loading @@ -306,6 +311,8 @@ public class ServiceStateTracker extends Handler { private static final int EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST = 59; private static final int EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST = 60; private static final int EVENT_ON_DEVICE_IDLE_STATE_CHANGED = 61; // Timeout event used when delaying radio power off to wait for IMS deregistration to happen. private static final int EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT = 62; /** * The current service state. Loading Loading @@ -340,12 +347,8 @@ public class ServiceStateTracker extends Handler { private CarrierDisplayNameResolver mCdnr; private boolean mImsRegistrationOnOff = false; private boolean mAlarmSwitch = false; /** Radio is disabled by carrier. Radio power will not be override if this field is set */ private boolean mRadioDisabledByCarrier = false; private PendingIntent mRadioOffIntent = null; private static final String ACTION_RADIO_OFF = "android.intent.action.ACTION_RADIO_OFF"; private boolean mPowerOffDelayNeed = true; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private boolean mDeviceShuttingDown = false; /** Keep track of SPN display rules, so we only broadcast intent if something changes. */ Loading Loading @@ -591,9 +594,6 @@ public class ServiceStateTracker extends Handler { if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) { // Update emergency string or operator name, polling service state. pollState(); } else if (intent.getAction().equals(ACTION_RADIO_OFF)) { mAlarmSwitch = false; powerOffRadioSafely(); } else if (intent.getAction().equals(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)) { String lastKnownNetworkCountry = intent.getStringExtra( TelephonyManager.EXTRA_LAST_KNOWN_NETWORK_COUNTRY); Loading Loading @@ -727,14 +727,7 @@ public class ServiceStateTracker extends Handler { Context context = mPhone.getContext(); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_LOCALE_CHANGED); context.registerReceiver(mIntentReceiver, filter); filter = new IntentFilter(); filter.addAction(ACTION_RADIO_OFF); context.registerReceiver(mIntentReceiver, filter); filter = new IntentFilter(); filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); context.registerReceiver(mIntentReceiver, filter); filter = new IntentFilter(); filter.addAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED); context.registerReceiver(mIntentReceiver, filter); Loading Loading @@ -874,6 +867,7 @@ public class ServiceStateTracker extends Handler { mCi.unregisterForImsNetworkStateChanged(this); mPhone.getCarrierActionAgent().unregisterForCarrierAction(this, CARRIER_ACTION_SET_RADIO_ENABLED); mPhone.getContext().unregisterReceiver(mIntentReceiver); if (mCSST != null) { mCSST.dispose(); mCSST = null; Loading Loading @@ -1840,6 +1834,12 @@ public class ServiceStateTracker extends Handler { break; } case EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT: { if (DBG) log("EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT triggered"); powerOffRadioSafely(); break; } default: log("Unhandled message with number: " + msg.what); break; Loading Loading @@ -3190,24 +3190,16 @@ public class ServiceStateTracker extends Handler { protected void setPowerStateToDesired(boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, boolean forceApply) { if (DBG) { String tmpLog = "mDeviceShuttingDown=" + mDeviceShuttingDown + String tmpLog = "setPowerStateToDesired: mDeviceShuttingDown=" + mDeviceShuttingDown + ", mDesiredPowerState=" + mDesiredPowerState + ", getRadioState=" + mCi.getRadioState() + ", mPowerOffDelayNeed=" + mPowerOffDelayNeed + ", mAlarmSwitch=" + mAlarmSwitch + ", mRadioDisabledByCarrier=" + mRadioDisabledByCarrier; ", mRadioDisabledByCarrier=" + mRadioDisabledByCarrier + ", IMS reg state=" + mImsRegistrationOnOff + ", pending radio off=" + hasMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT); log(tmpLog); mRadioPowerLog.log(tmpLog); } if (mAlarmSwitch) { if(DBG) log("mAlarmSwitch == true"); Context context = mPhone.getContext(); AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); am.cancel(mRadioOffIntent); mAlarmSwitch = false; } // If we want it on and it's off, turn it on if (mDesiredPowerState && !mRadioDisabledByCarrier && (forceApply || mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF)) { Loading @@ -3215,30 +3207,50 @@ public class ServiceStateTracker extends Handler { } else if ((!mDesiredPowerState || mRadioDisabledByCarrier) && mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) { // If it's on and available and we want it off gracefully if (mPowerOffDelayNeed) { if (mImsRegistrationOnOff && !mAlarmSwitch) { if(DBG) log("mImsRegistrationOnOff == true"); Context context = mPhone.getContext(); AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(ACTION_RADIO_OFF); mRadioOffIntent = PendingIntent.getBroadcast( context, 0, intent, PendingIntent.FLAG_IMMUTABLE); mAlarmSwitch = true; if (DBG) log("Alarm setting"); am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 3000, mRadioOffIntent); } else { powerOffRadioSafely(); } if (mImsRegistrationOnOff) { 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: powering off"); powerOffRadioSafely(); } } else if (mDeviceShuttingDown && (mCi.getRadioState() != TelephonyManager.RADIO_POWER_UNAVAILABLE)) { // !mDesiredPowerState condition above will happen first if the radio is on, so we will // see the following: (delay for IMS dereg) -> RADIO_POWER_OFF -> // RADIO_POWER_UNAVAILABLE mCi.requestShutdown(null); } // Cancel any pending timeouts because the state has been re-evaluated. cancelDelayRadioOffWaitingForImsDeregTimeout(); } /** * Cancel the EVENT_POWER_OFF_RADIO_DELAYED event if it is currently pending to be completed. * @return true if there was a pending timeout message in the queue, false otherwise. */ private void cancelDelayRadioOffWaitingForImsDeregTimeout() { if (hasMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT)) { if (DBG) log("cancelDelayRadioOffWaitingForImsDeregTimeout: cancelling."); removeMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT); } } /** * Start a timer to turn off the radio if IMS does not move to deregistered after the * radio power off event occurred. If this event already exists in the message queue, then * ignore the new request and use the existing one. */ private void startDelayRadioOffWaitingForImsDeregTimeout() { if (hasMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT)) { if (DBG) log("startDelayRadioOffWaitingForImsDeregTimeout: timer exists, ignoring"); return; } if (DBG) log("startDelayRadioOffWaitingForImsDeregTimeout: starting timer"); sendEmptyMessageDelayed(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT, DELAY_RADIO_OFF_FOR_IMS_DEREG_TIMEOUT); } protected void onUpdateIccAvailability() { Loading Loading @@ -3361,22 +3373,12 @@ public class ServiceStateTracker extends Handler { public void setImsRegistrationState(final boolean registered) { log("setImsRegistrationState: {registered=" + registered + " mImsRegistrationOnOff=" + mImsRegistrationOnOff + " mAlarmSwitch=" + mAlarmSwitch + "}"); if (mImsRegistrationOnOff && !registered) { if (mAlarmSwitch) { mImsRegistrationOnOff = registered; final Context context = mPhone.getContext(); final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); am.cancel(mRadioOffIntent); mAlarmSwitch = false; if (mImsRegistrationOnOff && !registered) { // moving to deregistered, only send this event if we need to re-evaluate sendMessage(obtainMessage(EVENT_CHANGE_IMS_STATE)); return; } } mImsRegistrationOnOff = registered; } Loading Loading @@ -5051,7 +5053,9 @@ public class ServiceStateTracker extends Handler { Phone.REASON_RADIO_TURNED_OFF); } } if (DBG) log("Data disconnected, turn off radio right away."); if (DBG) { log("powerOffRadioSafely: Data disconnected, turn off radio now."); } hangupAndPowerOff(); } else { // hang up all active voice calls first Loading @@ -5070,7 +5074,7 @@ public class ServiceStateTracker extends Handler { if (dds != mPhone.getSubId() && !ProxyController.getInstance().areAllDataDisconnected(dds)) { if (DBG) { log(String.format("Data is active on DDS (%d)." log(String.format("powerOffRadioSafely: Data is active on DDS (%d)." + " Wait for all data disconnect", dds)); } // Data is not disconnected on DDS. Wait for the data disconnect complete Loading @@ -5083,10 +5087,14 @@ public class ServiceStateTracker extends Handler { msg.what = EVENT_SET_RADIO_POWER_OFF; msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag; if (sendMessageDelayed(msg, 30000)) { if (DBG) log("Wait up to 30s for data to disconnect, then turn off radio."); if (DBG) { log("powerOffRadioSafely: Wait up to 30s for data to isconnect, then" + " turn off radio."); } mPendingRadioPowerOffAfterDataOff = true; } else { log("Cannot send delayed Msg, turn off radio right away."); log("powerOffRadioSafely: Cannot send delayed Msg, turn off radio right" + " away."); hangupAndPowerOff(); mPendingRadioPowerOffAfterDataOff = false; } Loading Loading @@ -5609,9 +5617,9 @@ public class ServiceStateTracker extends Handler { pw.flush(); pw.println(" mImsRegistered=" + mImsRegistered); pw.println(" mImsRegistrationOnOff=" + mImsRegistrationOnOff); pw.println(" mAlarmSwitch=" + mAlarmSwitch); pw.println(" pending radio off event=" + hasMessages(DELAY_RADIO_OFF_FOR_IMS_DEREG_TIMEOUT)); pw.println(" mRadioDisabledByCarrier" + mRadioDisabledByCarrier); pw.println(" mPowerOffDelayNeed=" + mPowerOffDelayNeed); pw.println(" mDeviceShuttingDown=" + mDeviceShuttingDown); pw.println(" mSpnUpdatePending=" + mSpnUpdatePending); pw.println(" mLteRsrpBoost=" + mLteRsrpBoost); Loading tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +69 −7 Original line number Diff line number Diff line Loading @@ -36,10 +36,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -127,8 +125,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { private ProxyController mProxyController; @Mock private Handler mTestHandler; @Mock protected AlarmManager mAlarmManager; private CellularNetworkService mCellularNetworkService; Loading Loading @@ -235,8 +231,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { logd("ServiceStateTrackerTest +Setup!"); super.setUp("ServiceStateTrackerTest"); doReturn(mAlarmManager).when(mContext).getSystemService(eq(Context.ALARM_SERVICE)); mContextFixture.putResource(R.string.config_wwan_network_service_package, "com.android.phone"); mContextFixture.putResource(R.string.config_wlan_network_service_package, Loading Loading @@ -1937,11 +1931,79 @@ public class ServiceStateTrackerTest extends TelephonyTest { waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); sst.setImsRegistrationState(false); verify(mAlarmManager).cancel(any(PendingIntent.class)); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertEquals(TelephonyManager.RADIO_POWER_UNAVAILABLE, mSimulatedCommands.getRadioState()); } @Test @SmallTest public void testImsRegisteredDelayShutDown() throws Exception { doReturn(true).when(mPhone).isPhoneTypeGsm(); sst.setImsRegistrationState(true); mSimulatedCommands.setRadioPowerFailResponse(false); sst.setRadioPower(true); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); // Turn off the radio and ensure radio power is still on assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); sst.setRadioPower(false); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); // Now set IMS reg state to false and ensure we see the modem move to power off. sst.setImsRegistrationState(false); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); } @Test @SmallTest public void testImsRegisteredDelayShutDownTimeout() throws Exception { doReturn(true).when(mPhone).isPhoneTypeGsm(); sst.setImsRegistrationState(true); mSimulatedCommands.setRadioPowerFailResponse(false); sst.setRadioPower(true); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); // Turn off the radio and ensure radio power is still on assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); sst.setRadioPower(false); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); // Ensure that if we never turn deregister for IMS, we still eventually see radio state // move to off. // Timeout for IMS reg + some extra time to remove race conditions waitForDelayedHandlerAction(mSSTTestHandler.getThreadHandler(), ServiceStateTracker.DELAY_RADIO_OFF_FOR_IMS_DEREG_TIMEOUT + 100, 1000); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); } @Test @SmallTest public void testImsRegisteredAPMOnOffToggle() throws Exception { doReturn(true).when(mPhone).isPhoneTypeGsm(); sst.setImsRegistrationState(true); mSimulatedCommands.setRadioPowerFailResponse(false); sst.setRadioPower(true); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); // Turn off the radio and ensure radio power is still on and then turn it back on again assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); sst.setRadioPower(false); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); sst.setRadioPower(true); assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); // Ensure the timeout was cancelled and we still see radio power is on. // Timeout for IMS reg + some extra time to remove race conditions waitForDelayedHandlerAction(mSSTTestHandler.getThreadHandler(), ServiceStateTracker.DELAY_RADIO_OFF_FOR_IMS_DEREG_TIMEOUT + 100, 1000); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); } @Test @SmallTest public void testSetTimeFromNITZStr() throws Exception { Loading tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +13 −0 Original line number Diff line number Diff line Loading @@ -934,6 +934,19 @@ public abstract class TelephonyTest { mockTelephonyManager).getCarrierPrivilegeStatus(anyInt()); } protected final void waitForDelayedHandlerAction(Handler h, long delayMillis, long timeoutMillis) { final CountDownLatch lock = new CountDownLatch(1); h.postDelayed(lock::countDown, delayMillis); while (lock.getCount() > 0) { try { lock.await(delayMillis + timeoutMillis, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { // do nothing } } } protected final void waitForHandlerAction(Handler h, long timeoutMillis) { final CountDownLatch lock = new CountDownLatch(1); h.post(lock::countDown); Loading Loading
src/java/com/android/internal/telephony/ServiceStateTracker.java +74 −66 Original line number Diff line number Diff line Loading @@ -25,10 +25,8 @@ import static com.android.internal.telephony.uicc.IccRecords.CARRIER_NAME_DISPLA import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ContentResolver; Loading Loading @@ -251,6 +249,12 @@ public class ServiceStateTracker extends Handler { /** Signal strength poll rate. */ private static final int POLL_PERIOD_MILLIS = 20 * 1000; /** * The time we wait for IMS to deregister before executing a pending radio power off request. */ @VisibleForTesting public static final int DELAY_RADIO_OFF_FOR_IMS_DEREG_TIMEOUT = 3 * 1000; /** Waiting period before recheck gprs and voice registration. */ public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; Loading Loading @@ -290,6 +294,7 @@ public class ServiceStateTracker extends Handler { public static final int EVENT_ICC_CHANGED = 42; protected static final int EVENT_GET_CELL_INFO_LIST = 43; protected static final int EVENT_UNSOL_CELL_INFO_LIST = 44; // Only sent if the IMS state is moving from true -> false protected static final int EVENT_CHANGE_IMS_STATE = 45; protected static final int EVENT_IMS_STATE_CHANGED = 46; protected static final int EVENT_IMS_STATE_DONE = 47; Loading @@ -306,6 +311,8 @@ public class ServiceStateTracker extends Handler { private static final int EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST = 59; private static final int EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST = 60; private static final int EVENT_ON_DEVICE_IDLE_STATE_CHANGED = 61; // Timeout event used when delaying radio power off to wait for IMS deregistration to happen. private static final int EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT = 62; /** * The current service state. Loading Loading @@ -340,12 +347,8 @@ public class ServiceStateTracker extends Handler { private CarrierDisplayNameResolver mCdnr; private boolean mImsRegistrationOnOff = false; private boolean mAlarmSwitch = false; /** Radio is disabled by carrier. Radio power will not be override if this field is set */ private boolean mRadioDisabledByCarrier = false; private PendingIntent mRadioOffIntent = null; private static final String ACTION_RADIO_OFF = "android.intent.action.ACTION_RADIO_OFF"; private boolean mPowerOffDelayNeed = true; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private boolean mDeviceShuttingDown = false; /** Keep track of SPN display rules, so we only broadcast intent if something changes. */ Loading Loading @@ -591,9 +594,6 @@ public class ServiceStateTracker extends Handler { if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) { // Update emergency string or operator name, polling service state. pollState(); } else if (intent.getAction().equals(ACTION_RADIO_OFF)) { mAlarmSwitch = false; powerOffRadioSafely(); } else if (intent.getAction().equals(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)) { String lastKnownNetworkCountry = intent.getStringExtra( TelephonyManager.EXTRA_LAST_KNOWN_NETWORK_COUNTRY); Loading Loading @@ -727,14 +727,7 @@ public class ServiceStateTracker extends Handler { Context context = mPhone.getContext(); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_LOCALE_CHANGED); context.registerReceiver(mIntentReceiver, filter); filter = new IntentFilter(); filter.addAction(ACTION_RADIO_OFF); context.registerReceiver(mIntentReceiver, filter); filter = new IntentFilter(); filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); context.registerReceiver(mIntentReceiver, filter); filter = new IntentFilter(); filter.addAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED); context.registerReceiver(mIntentReceiver, filter); Loading Loading @@ -874,6 +867,7 @@ public class ServiceStateTracker extends Handler { mCi.unregisterForImsNetworkStateChanged(this); mPhone.getCarrierActionAgent().unregisterForCarrierAction(this, CARRIER_ACTION_SET_RADIO_ENABLED); mPhone.getContext().unregisterReceiver(mIntentReceiver); if (mCSST != null) { mCSST.dispose(); mCSST = null; Loading Loading @@ -1840,6 +1834,12 @@ public class ServiceStateTracker extends Handler { break; } case EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT: { if (DBG) log("EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT triggered"); powerOffRadioSafely(); break; } default: log("Unhandled message with number: " + msg.what); break; Loading Loading @@ -3190,24 +3190,16 @@ public class ServiceStateTracker extends Handler { protected void setPowerStateToDesired(boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, boolean forceApply) { if (DBG) { String tmpLog = "mDeviceShuttingDown=" + mDeviceShuttingDown + String tmpLog = "setPowerStateToDesired: mDeviceShuttingDown=" + mDeviceShuttingDown + ", mDesiredPowerState=" + mDesiredPowerState + ", getRadioState=" + mCi.getRadioState() + ", mPowerOffDelayNeed=" + mPowerOffDelayNeed + ", mAlarmSwitch=" + mAlarmSwitch + ", mRadioDisabledByCarrier=" + mRadioDisabledByCarrier; ", mRadioDisabledByCarrier=" + mRadioDisabledByCarrier + ", IMS reg state=" + mImsRegistrationOnOff + ", pending radio off=" + hasMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT); log(tmpLog); mRadioPowerLog.log(tmpLog); } if (mAlarmSwitch) { if(DBG) log("mAlarmSwitch == true"); Context context = mPhone.getContext(); AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); am.cancel(mRadioOffIntent); mAlarmSwitch = false; } // If we want it on and it's off, turn it on if (mDesiredPowerState && !mRadioDisabledByCarrier && (forceApply || mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF)) { Loading @@ -3215,30 +3207,50 @@ public class ServiceStateTracker extends Handler { } else if ((!mDesiredPowerState || mRadioDisabledByCarrier) && mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) { // If it's on and available and we want it off gracefully if (mPowerOffDelayNeed) { if (mImsRegistrationOnOff && !mAlarmSwitch) { if(DBG) log("mImsRegistrationOnOff == true"); Context context = mPhone.getContext(); AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(ACTION_RADIO_OFF); mRadioOffIntent = PendingIntent.getBroadcast( context, 0, intent, PendingIntent.FLAG_IMMUTABLE); mAlarmSwitch = true; if (DBG) log("Alarm setting"); am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 3000, mRadioOffIntent); } else { powerOffRadioSafely(); } if (mImsRegistrationOnOff) { 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: powering off"); powerOffRadioSafely(); } } else if (mDeviceShuttingDown && (mCi.getRadioState() != TelephonyManager.RADIO_POWER_UNAVAILABLE)) { // !mDesiredPowerState condition above will happen first if the radio is on, so we will // see the following: (delay for IMS dereg) -> RADIO_POWER_OFF -> // RADIO_POWER_UNAVAILABLE mCi.requestShutdown(null); } // Cancel any pending timeouts because the state has been re-evaluated. cancelDelayRadioOffWaitingForImsDeregTimeout(); } /** * Cancel the EVENT_POWER_OFF_RADIO_DELAYED event if it is currently pending to be completed. * @return true if there was a pending timeout message in the queue, false otherwise. */ private void cancelDelayRadioOffWaitingForImsDeregTimeout() { if (hasMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT)) { if (DBG) log("cancelDelayRadioOffWaitingForImsDeregTimeout: cancelling."); removeMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT); } } /** * Start a timer to turn off the radio if IMS does not move to deregistered after the * radio power off event occurred. If this event already exists in the message queue, then * ignore the new request and use the existing one. */ private void startDelayRadioOffWaitingForImsDeregTimeout() { if (hasMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT)) { if (DBG) log("startDelayRadioOffWaitingForImsDeregTimeout: timer exists, ignoring"); return; } if (DBG) log("startDelayRadioOffWaitingForImsDeregTimeout: starting timer"); sendEmptyMessageDelayed(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT, DELAY_RADIO_OFF_FOR_IMS_DEREG_TIMEOUT); } protected void onUpdateIccAvailability() { Loading Loading @@ -3361,22 +3373,12 @@ public class ServiceStateTracker extends Handler { public void setImsRegistrationState(final boolean registered) { log("setImsRegistrationState: {registered=" + registered + " mImsRegistrationOnOff=" + mImsRegistrationOnOff + " mAlarmSwitch=" + mAlarmSwitch + "}"); if (mImsRegistrationOnOff && !registered) { if (mAlarmSwitch) { mImsRegistrationOnOff = registered; final Context context = mPhone.getContext(); final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); am.cancel(mRadioOffIntent); mAlarmSwitch = false; if (mImsRegistrationOnOff && !registered) { // moving to deregistered, only send this event if we need to re-evaluate sendMessage(obtainMessage(EVENT_CHANGE_IMS_STATE)); return; } } mImsRegistrationOnOff = registered; } Loading Loading @@ -5051,7 +5053,9 @@ public class ServiceStateTracker extends Handler { Phone.REASON_RADIO_TURNED_OFF); } } if (DBG) log("Data disconnected, turn off radio right away."); if (DBG) { log("powerOffRadioSafely: Data disconnected, turn off radio now."); } hangupAndPowerOff(); } else { // hang up all active voice calls first Loading @@ -5070,7 +5074,7 @@ public class ServiceStateTracker extends Handler { if (dds != mPhone.getSubId() && !ProxyController.getInstance().areAllDataDisconnected(dds)) { if (DBG) { log(String.format("Data is active on DDS (%d)." log(String.format("powerOffRadioSafely: Data is active on DDS (%d)." + " Wait for all data disconnect", dds)); } // Data is not disconnected on DDS. Wait for the data disconnect complete Loading @@ -5083,10 +5087,14 @@ public class ServiceStateTracker extends Handler { msg.what = EVENT_SET_RADIO_POWER_OFF; msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag; if (sendMessageDelayed(msg, 30000)) { if (DBG) log("Wait up to 30s for data to disconnect, then turn off radio."); if (DBG) { log("powerOffRadioSafely: Wait up to 30s for data to isconnect, then" + " turn off radio."); } mPendingRadioPowerOffAfterDataOff = true; } else { log("Cannot send delayed Msg, turn off radio right away."); log("powerOffRadioSafely: Cannot send delayed Msg, turn off radio right" + " away."); hangupAndPowerOff(); mPendingRadioPowerOffAfterDataOff = false; } Loading Loading @@ -5609,9 +5617,9 @@ public class ServiceStateTracker extends Handler { pw.flush(); pw.println(" mImsRegistered=" + mImsRegistered); pw.println(" mImsRegistrationOnOff=" + mImsRegistrationOnOff); pw.println(" mAlarmSwitch=" + mAlarmSwitch); pw.println(" pending radio off event=" + hasMessages(DELAY_RADIO_OFF_FOR_IMS_DEREG_TIMEOUT)); pw.println(" mRadioDisabledByCarrier" + mRadioDisabledByCarrier); pw.println(" mPowerOffDelayNeed=" + mPowerOffDelayNeed); pw.println(" mDeviceShuttingDown=" + mDeviceShuttingDown); pw.println(" mSpnUpdatePending=" + mSpnUpdatePending); pw.println(" mLteRsrpBoost=" + mLteRsrpBoost); Loading
tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +69 −7 Original line number Diff line number Diff line Loading @@ -36,10 +36,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -127,8 +125,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { private ProxyController mProxyController; @Mock private Handler mTestHandler; @Mock protected AlarmManager mAlarmManager; private CellularNetworkService mCellularNetworkService; Loading Loading @@ -235,8 +231,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { logd("ServiceStateTrackerTest +Setup!"); super.setUp("ServiceStateTrackerTest"); doReturn(mAlarmManager).when(mContext).getSystemService(eq(Context.ALARM_SERVICE)); mContextFixture.putResource(R.string.config_wwan_network_service_package, "com.android.phone"); mContextFixture.putResource(R.string.config_wlan_network_service_package, Loading Loading @@ -1937,11 +1931,79 @@ public class ServiceStateTrackerTest extends TelephonyTest { waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); sst.setImsRegistrationState(false); verify(mAlarmManager).cancel(any(PendingIntent.class)); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertEquals(TelephonyManager.RADIO_POWER_UNAVAILABLE, mSimulatedCommands.getRadioState()); } @Test @SmallTest public void testImsRegisteredDelayShutDown() throws Exception { doReturn(true).when(mPhone).isPhoneTypeGsm(); sst.setImsRegistrationState(true); mSimulatedCommands.setRadioPowerFailResponse(false); sst.setRadioPower(true); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); // Turn off the radio and ensure radio power is still on assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); sst.setRadioPower(false); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); // Now set IMS reg state to false and ensure we see the modem move to power off. sst.setImsRegistrationState(false); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); } @Test @SmallTest public void testImsRegisteredDelayShutDownTimeout() throws Exception { doReturn(true).when(mPhone).isPhoneTypeGsm(); sst.setImsRegistrationState(true); mSimulatedCommands.setRadioPowerFailResponse(false); sst.setRadioPower(true); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); // Turn off the radio and ensure radio power is still on assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); sst.setRadioPower(false); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); // Ensure that if we never turn deregister for IMS, we still eventually see radio state // move to off. // Timeout for IMS reg + some extra time to remove race conditions waitForDelayedHandlerAction(mSSTTestHandler.getThreadHandler(), ServiceStateTracker.DELAY_RADIO_OFF_FOR_IMS_DEREG_TIMEOUT + 100, 1000); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); } @Test @SmallTest public void testImsRegisteredAPMOnOffToggle() throws Exception { doReturn(true).when(mPhone).isPhoneTypeGsm(); sst.setImsRegistrationState(true); mSimulatedCommands.setRadioPowerFailResponse(false); sst.setRadioPower(true); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); // Turn off the radio and ensure radio power is still on and then turn it back on again assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); sst.setRadioPower(false); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); sst.setRadioPower(true); assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); // Ensure the timeout was cancelled and we still see radio power is on. // Timeout for IMS reg + some extra time to remove race conditions waitForDelayedHandlerAction(mSSTTestHandler.getThreadHandler(), ServiceStateTracker.DELAY_RADIO_OFF_FOR_IMS_DEREG_TIMEOUT + 100, 1000); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); } @Test @SmallTest public void testSetTimeFromNITZStr() throws Exception { Loading
tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +13 −0 Original line number Diff line number Diff line Loading @@ -934,6 +934,19 @@ public abstract class TelephonyTest { mockTelephonyManager).getCarrierPrivilegeStatus(anyInt()); } protected final void waitForDelayedHandlerAction(Handler h, long delayMillis, long timeoutMillis) { final CountDownLatch lock = new CountDownLatch(1); h.postDelayed(lock::countDown, delayMillis); while (lock.getCount() > 0) { try { lock.await(delayMillis + timeoutMillis, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { // do nothing } } } protected final void waitForHandlerAction(Handler h, long timeoutMillis) { final CountDownLatch lock = new CountDownLatch(1); h.post(lock::countDown); Loading