Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef824018 authored by Sarah Chin's avatar Sarah Chin
Browse files

New data stack wait for data disconnected on all subs for APM on

Test: manually verify APM on/off behavior
Test: atest ServiceStateTrackerTest, DataNetworkControllerTest
Bug: 230679305
Change-Id: I12d7b67236bccbfa6fee4cb21c6dc91bb45e6ebc
parent 932f8ae0
Loading
Loading
Loading
Loading
+49 −36
Original line number Diff line number Diff line
@@ -285,7 +285,6 @@ public class ServiceStateTracker extends Handler {
    // 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;
    protected static final int EVENT_RESET_LAST_KNOWN_CELL_IDENTITY    = 63;
    private static final int EVENT_REGISTER_DATA_NETWORK_EXISTING_CHANGED = 64;
    // Telecom has un/registered a PhoneAccount that provides OTT voice calling capability, e.g.
    // wi-fi calling.
    protected static final int EVENT_TELECOM_VOICE_SERVICE_STATE_OVERRIDE_CHANGED = 65;
@@ -620,11 +619,11 @@ public class ServiceStateTracker extends Handler {
    private int mLastKnownAreaCode = CellInfo.UNAVAILABLE;

    /**
     * Indicating if there is any data network existing. This is used in airplane mode turning on
     * scenario, where service state tracker should wait all data disconnected before powering
     * down the modem.
     * Data network controller callback for all data disconnected. This is used when turning on
     * airplane mode, where service state tracker should wait for all data disconnected on all
     * subscriptions before powering down the modem.
     */
    private boolean mAnyDataExisting = false;
    private DataNetworkControllerCallback mDataDisconnectedCallback;

    public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
        mNitzState = TelephonyComponentFactory.getInstance()
@@ -722,7 +721,15 @@ public class ServiceStateTracker extends Handler {
                CarrierServiceStateTracker.CARRIER_EVENT_IMS_CAPABILITIES_CHANGED, null);

        if (mPhone.isUsingNewDataStack()) {
            sendEmptyMessage(EVENT_REGISTER_DATA_NETWORK_EXISTING_CHANGED);
            mDataDisconnectedCallback = new DataNetworkControllerCallback(this::post) {
                @Override
                public void onAnyDataNetworkExistingChanged(boolean anyDataExisting) {
                    log("onAnyDataNetworkExistingChanged: anyDataExisting=" + anyDataExisting);
                    if (!anyDataExisting) {
                        sendEmptyMessage(EVENT_ALL_DATA_DISCONNECTED);
                    }
                }
            };
        }
    }

@@ -1471,30 +1478,26 @@ public class ServiceStateTracker extends Handler {
                }
                break;

            case EVENT_REGISTER_DATA_NETWORK_EXISTING_CHANGED: {
                mPhone.getDataNetworkController().registerDataNetworkControllerCallback(
                        new DataNetworkControllerCallback(this::post) {
                        @Override
                        public void onAnyDataNetworkExistingChanged(boolean anyDataExisting) {
                            if (mAnyDataExisting != anyDataExisting) {
                                mAnyDataExisting = anyDataExisting;
                                log("onAnyDataNetworkExistingChanged: anyDataExisting="
                                        + anyDataExisting);
                                if (!mAnyDataExisting) {
                                    sendEmptyMessage(EVENT_ALL_DATA_DISCONNECTED);
                                }
                            }
                        }
                        });
                break;
            }
            case EVENT_ALL_DATA_DISCONNECTED:
                if (mPhone.isUsingNewDataStack()) {
                    log("EVENT_ALL_DATA_DISCONNECTED");
                    if (mPendingRadioPowerOffAfterDataOff) {
                    if (!mPendingRadioPowerOffAfterDataOff) return;
                    boolean areAllDataDisconnectedOnAllPhones = true;
                    for (Phone phone : PhoneFactory.getPhones()) {
                        if (phone.getDataNetworkController().areAllDataDisconnected()) {
                            phone.getDataNetworkController()
                                    .unregisterDataNetworkControllerCallback(
                                            mDataDisconnectedCallback);
                        } else {
                            log("Still waiting for all data disconnected on phone: "
                                    + phone.getSubId());
                            areAllDataDisconnectedOnAllPhones = false;
                        }
                    }
                    if (areAllDataDisconnectedOnAllPhones) {
                        mPendingRadioPowerOffAfterDataOff = false;
                        removeMessages(EVENT_SET_RADIO_POWER_OFF);
                        if (DBG) log("EVENT_ALL_DATA_DISCONNECTED, turn radio off now.");
                        if (DBG) log("Data disconnected for all phones, turn radio off now.");
                        hangupAndPowerOff();
                    }
                    return;
@@ -5017,17 +5020,28 @@ public class ServiceStateTracker extends Handler {
                        mPhone.mCT.mBackgroundCall.hangupIfAlive();
                        mPhone.mCT.mForegroundCall.hangupIfAlive();
                    }
                    if (mAnyDataExisting) {
                        log("powerOffRadioSafely: Tear down all data networks.");

                    for (Phone phone : PhoneFactory.getPhones()) {
                        if (!phone.getDataNetworkController().areAllDataDisconnected()) {
                            log("powerOffRadioSafely: Data is active on phone " + phone.getSubId()
                                    + ". Wait for all data disconnect.");
                            mPendingRadioPowerOffAfterDataOff = true;
                            phone.getDataNetworkController().registerDataNetworkControllerCallback(
                                    mDataDisconnectedCallback);
                        }
                    }

                    // Tear down outside of the disconnected check to prevent race conditions.
                    mPhone.getDataNetworkController().tearDownAllDataNetworks(
                            DataNetwork.TEAR_DOWN_REASON_AIRPLANE_MODE_ON);

                    if (mPendingRadioPowerOffAfterDataOff) {
                        sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF,
                                POWER_OFF_ALL_DATA_NETWORKS_DISCONNECTED_TIMEOUT);
                    } else {
                        log("powerOffRadioSafely: No data is connected.");
                        sendEmptyMessage(EVENT_ALL_DATA_DISCONNECTED);
                        log("powerOffRadioSafely: No data is connected, turn off radio now.");
                        hangupAndPowerOff();
                    }
                    mPendingRadioPowerOffAfterDataOff = true;
                    return;
                }
                int dds = SubscriptionManager.getDefaultDataSubscriptionId();
@@ -5079,8 +5093,8 @@ public class ServiceStateTracker extends Handler {
                    msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag;
                    if (sendMessageDelayed(msg, 30000)) {
                        if (DBG) {
                            log("powerOffRadioSafely: Wait up to 30s for data to isconnect, then"
                                    + " turn off radio.");
                            log("powerOffRadioSafely: Wait up to 30s for data to disconnect, "
                                    + "then turn off radio.");
                        }
                        mPendingRadioPowerOffAfterDataOff = true;
                    } else {
@@ -5344,7 +5358,6 @@ public class ServiceStateTracker extends Handler {
        dumpCellInfoList(pw);
        pw.flush();
        pw.println(" mAllowedNetworkTypes=" + mAllowedNetworkTypes);
        pw.println(" mAnyDataExisting=" + mAnyDataExisting);
        pw.println(" mMaxDataCalls=" + mMaxDataCalls);
        pw.println(" mNewMaxDataCalls=" + mNewMaxDataCalls);
        pw.println(" mReasonDataDenied=" + mReasonDataDenied);
+19 −3
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.internal.telephony.data;


import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -1082,7 +1081,13 @@ public class DataNetworkController extends Handler {
                onTearDownAllDataNetworks(msg.arg1);
                break;
            case EVENT_REGISTER_DATA_NETWORK_CONTROLLER_CALLBACK:
                mDataNetworkControllerCallbacks.add((DataNetworkControllerCallback) msg.obj);
                DataNetworkControllerCallback callback = (DataNetworkControllerCallback) msg.obj;
                mDataNetworkControllerCallbacks.add(callback);
                // Notify upon registering if no data networks currently exist.
                if (mDataNetworkList.isEmpty()) {
                    callback.invokeFromExecutor(
                            () -> callback.onAnyDataNetworkExistingChanged(false));
                }
                break;
            case EVENT_UNREGISTER_DATA_NETWORK_CONTROLLER_CALLBACK:
                mDataNetworkControllerCallbacks.remove((DataNetworkControllerCallback) msg.obj);
@@ -1337,7 +1342,7 @@ public class DataNetworkController extends Handler {
    }

    /**
     * @return {@code true} internet is unmetered.
     * @return {@code true} if internet is unmetered.
     */
    public boolean isInternetUnmetered() {
        return mDataNetworkList.stream()
@@ -1349,6 +1354,17 @@ public class DataNetworkController extends Handler {
                        .hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED));
    }

    /**
     * @return {@code true} if all data networks are disconnected.
     */
    public boolean areAllDataDisconnected() {
        if (!mDataNetworkList.isEmpty()) {
            log("areAllDataDisconnected false due to: " + mDataNetworkList.stream()
                    .map(DataNetwork::name).collect(Collectors.joining(", ")));
        }
        return mDataNetworkList.isEmpty();
    }

    /**
     * @return List of the reasons why internet data is not allowed. An empty list if internet
     * is allowed.
+55 −0
Original line number Diff line number Diff line
@@ -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;
@@ -235,6 +236,7 @@ public class ServiceStateTrackerTest extends TelephonyTest {
        addNetworkService();

        doReturn(true).when(mDcTracker).areAllDataDisconnected();
        doReturn(true).when(mDataNetworkController).areAllDataDisconnected();

        doReturn(new ServiceState()).when(mPhone).getServiceState();

@@ -379,6 +381,59 @@ public class ServiceStateTrackerTest extends TelephonyTest {
                != (mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_ON));
    }

    @Test
    public void testSetRadioPowerWaitForAllDataDisconnected() throws Exception {
        // Set up DSDS environment
        GsmCdmaPhone phone2 = Mockito.mock(GsmCdmaPhone.class);
        DataNetworkController dataNetworkController_phone2 =
                Mockito.mock(DataNetworkController.class);
        mPhones = new Phone[] {mPhone, phone2};
        replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
        doReturn(dataNetworkController_phone2).when(phone2).getDataNetworkController();
        doReturn(mSST).when(phone2).getServiceStateTracker();
        doReturn(true).when(phone2).isUsingNewDataStack();
        doReturn(false).when(mDataNetworkController).areAllDataDisconnected();
        doReturn(false).when(dataNetworkController_phone2).areAllDataDisconnected();
        doReturn(1).when(mPhone).getSubId();
        doReturn(2).when(phone2).getSubId();

        // Start with radio on
        sst.setRadioPower(true);
        waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
        assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState());

        // Turn on APM and verify that both subs are 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 */));
        verify(dataNetworkController_phone2, never()).tearDownAllDataNetworks(anyInt());
        ArgumentCaptor<DataNetworkController.DataNetworkControllerCallback> callback1 =
                ArgumentCaptor.forClass(DataNetworkController.DataNetworkControllerCallback.class);
        ArgumentCaptor<DataNetworkController.DataNetworkControllerCallback> callback2 =
                ArgumentCaptor.forClass(DataNetworkController.DataNetworkControllerCallback.class);
        verify(mDataNetworkController, times(1)).registerDataNetworkControllerCallback(
                callback1.capture());
        verify(dataNetworkController_phone2, times(1)).registerDataNetworkControllerCallback(
                callback2.capture());

        // Data disconnected on sub 2, still waiting for data disconnected on sub 1
        doReturn(true).when(dataNetworkController_phone2).areAllDataDisconnected();
        callback2.getValue().onAnyDataNetworkExistingChanged(false);
        waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
        assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState());
        verify(dataNetworkController_phone2, times(1)).unregisterDataNetworkControllerCallback(
                any());

        // Data disconnected on sub 1, radio should power off now
        doReturn(true).when(mDataNetworkController).areAllDataDisconnected();
        callback1.getValue().onAnyDataNetworkExistingChanged(false);
        waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
        verify(mDataNetworkController, times(1)).unregisterDataNetworkControllerCallback(any());
        assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState());
    }

    @Test
    @SmallTest
    public void testSetRadioPowerOnForEmergencyCall() {
+1 −0
Original line number Diff line number Diff line
@@ -811,6 +811,7 @@ public class DataNetworkControllerTest extends TelephonyTest {
        mRcsRegCallback = regCallbackCaptor.getValue();

        processAllMessages();
        Mockito.clearInvocations(mMockedDataNetworkControllerCallback);

        logd("DataNetworkControllerTest -Setup!");
    }