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

Commit b5e7e19a authored by Hunsuk Choi's avatar Hunsuk Choi
Browse files

Block onWwanSelected until setEmergencyMode completes

Bug: 324543257
Test: atest EmergencyStateTrackerTest

Change-Id: I0a208c7a7e2c3491dfb21a6bf3776d5e5eb9d5bb
parent 0db6068c
Loading
Loading
Loading
Loading
+46 −18
Original line number Diff line number Diff line
@@ -138,14 +138,32 @@ public class DomainSelectionConnection {
                if (mWwanSelectorCallback == null) {
                    mWwanSelectorCallback = new WwanSelectorCallbackAdaptor();
                }
                if (mIsTestMode || !mIsEmergency
                        || (mSelectorType != DomainSelectionService.SELECTOR_TYPE_CALLING)) {
                    initHandler();
                    mHandler.post(() -> {
                        onWwanSelectedAsyncInternal(cb);
                    });
                } else {
                    Thread workerThread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            onWwanSelectedAsyncInternal(cb);
                        }
                    });
                    workerThread.start();
                }
            }
        }

        private void onWwanSelectedAsyncInternal(
                @NonNull final ITransportSelectorResultCallback cb) {
            synchronized (mLock) {
                if (checkState(STATUS_DISPOSED)) {
                    return;
                }
                        DomainSelectionConnection.this.onWwanSelected();
            }
            DomainSelectionConnection.this.onWwanSelected();
            try {
                cb.onCompleted(mWwanSelectorCallback);
            } catch (RemoteException e) {
@@ -156,8 +174,6 @@ public class DomainSelectionConnection {
                    waitForServiceBinding(null);
                }
            }
                });
            }
        }

        @Override
@@ -333,6 +349,8 @@ public class DomainSelectionConnection {

    private @Nullable ScanRequest mPendingScanRequest;

    private boolean mIsTestMode = false;

    /**
     * Creates an instance.
     *
@@ -760,6 +778,16 @@ public class DomainSelectionConnection {
        return (mStatus & stateBit) == stateBit;
    }

    /**
     * Set whether it is unit test or not.
     *
     * @param testMode Indicates whether it is unit test or not.
     */
    @VisibleForTesting
    public void setTestMode(boolean testMode) {
        mIsTestMode = testMode;
    }

    /**
     * Dumps local log.
     */
+1 −1
Original line number Diff line number Diff line
@@ -109,7 +109,7 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne
    /** {@inheritDoc} */
    @Override
    public void onWwanSelected() {
        mEmergencyStateTracker.onEmergencyTransportChanged(
        mEmergencyStateTracker.onEmergencyTransportChangedAndWait(
                EmergencyStateTracker.EMERGENCY_TYPE_CALL, MODE_EMERGENCY_WWAN);
    }

+76 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.preference.PreferenceManager;
import android.provider.Settings;
@@ -93,6 +94,8 @@ public class EmergencyStateTracker {
    private static final long DEFAULT_ECM_EXIT_TIMEOUT_MS = 300000;
    private static final int DEFAULT_EPDN_DISCONNECTION_TIMEOUT_MS = 500;

    private static final int DEFAULT_TRANSPORT_CHANGE_TIMEOUT_MS = 1 * 1000;

    /** The emergency types used when setting the emergency mode on modem. */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = "EMERGENCY_TYPE_",
@@ -150,6 +153,8 @@ public class EmergencyStateTracker {
    private CompletableFuture<Integer> mSmsEmergencyModeFuture;
    private boolean mIsTestEmergencyNumberForSms;

    private CompletableFuture<Boolean> mEmergencyTransportChangedFuture;

    private final android.util.ArrayMap<Integer, Boolean> mNoSimEcbmSupported =
            new android.util.ArrayMap<>();
    private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener =
@@ -297,6 +302,9 @@ public class EmergencyStateTracker {
                    }
                    setEmergencyModeInProgress(false);

                    // Transport changed from WLAN to WWAN or CALLBACK to WWAN
                    maybeNotifyTransportChangeCompleted(emergencyType, false);

                    if (emergencyType == EMERGENCY_TYPE_CALL) {
                        setIsInEmergencyCall(true);
                        completeEmergencyMode(emergencyType);
@@ -600,6 +608,9 @@ public class EmergencyStateTracker {
                clearEmergencyCallInfo();
            }
        }

        // Release any blocked thread immediately
        maybeNotifyTransportChangeCompleted(EMERGENCY_TYPE_CALL, true);
    }

    private void clearEmergencyCallInfo() {
@@ -643,6 +654,8 @@ public class EmergencyStateTracker {
                + emergencyTypeToString(emergencyType));

        if (mEmergencyMode == mode) {
            // Initial transport selection of DomainSelector
            maybeNotifyTransportChangeCompleted(emergencyType, false);
            return;
        }
        mEmergencyMode = mode;
@@ -816,6 +829,69 @@ public class EmergencyStateTracker {
        return mLastEmergencyRegistrationResult;
    }

    private void waitForTransportChangeCompleted(CompletableFuture<Boolean> future) {
        if (future != null) {
            synchronized (future) {
                if ((mEmergencyMode == MODE_EMERGENCY_NONE)
                        || mHandler.getLooper().isCurrentThread()) {
                    // Do not block the Handler's thread
                    return;
                }
                long now = SystemClock.elapsedRealtime();
                long deadline = now + DEFAULT_TRANSPORT_CHANGE_TIMEOUT_MS;
                // Guard with while loop to handle spurious wakeups
                while (!future.isDone() && now < deadline) {
                    try {
                        future.wait(deadline - now);
                    } catch (Exception e) {
                        Rlog.e(TAG, "waitForTransportChangeCompleted wait e=" + e);
                    }
                    now = SystemClock.elapsedRealtime();
                }
            }
        }
    }

    private void maybeNotifyTransportChangeCompleted(@EmergencyType int emergencyType,
            boolean enforced) {
        if (emergencyType != EMERGENCY_TYPE_CALL) {
            // It's not for the emergency call
            return;
        }
        CompletableFuture<Boolean> future = mEmergencyTransportChangedFuture;
        if (future != null) {
            synchronized (future) {
                if (!future.isDone()
                        && ((!isEmergencyModeInProgress() && mEmergencyMode == MODE_EMERGENCY_WWAN)
                                || enforced)) {
                    future.complete(Boolean.TRUE);
                    future.notifyAll();
                }
            }
        }
    }

    /**
     * Handles emergency transport change by setting new emergency mode.
     *
     * @param emergencyType the emergency type to identify an emergency call or SMS
     * @param mode the new emergency mode
     */
    public void onEmergencyTransportChangedAndWait(@EmergencyType int emergencyType,
            @EmergencyConstants.EmergencyMode int mode) {
        // Wait for the completion of setting MODE_EMERGENCY_WWAN only for emergency calls
        if (emergencyType == EMERGENCY_TYPE_CALL && mode == MODE_EMERGENCY_WWAN) {
            CompletableFuture<Boolean> future = new CompletableFuture<>();
            synchronized (future) {
                mEmergencyTransportChangedFuture = future;
                onEmergencyTransportChanged(emergencyType, mode);
                waitForTransportChangeCompleted(future);
            }
            return;
        }
        onEmergencyTransportChanged(emergencyType, mode);
    }

    /**
     * Handles emergency transport change by setting new emergency mode.
     *
+1 −0
Original line number Diff line number Diff line
@@ -777,6 +777,7 @@ public class DomainSelectionConnectionTest extends TelephonyTest {
            boolean isEmergency, DomainSelectionController controller) throws Exception {
        DomainSelectionConnection dsc = new DomainSelectionConnection(phone,
                selectorType, isEmergency, controller);
        dsc.setTestMode(true);
        replaceInstance(DomainSelectionConnection.class, "mLooper",
                dsc, mTestableLooper.getLooper());
        return dsc;
+3 −2
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest {
        doReturn(mAnm).when(mPhone).getAccessNetworksManager();
        mEcDsc = new EmergencyCallDomainSelectionConnection(mPhone,
                mDomainSelectionController, mEmergencyStateTracker);
        mEcDsc.setTestMode(true);
        replaceInstance(DomainSelectionConnection.class, "mLooper",
                mEcDsc, mTestableLooper.getLooper());
        mTransportCallback = mEcDsc.getTransportSelectorCallback();
@@ -184,7 +185,7 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest {
        IWwanSelectorCallback wwanCallback = onWwanSelected(mTransportCallback);

        assertFalse(future.isDone());
        verify(mEmergencyStateTracker).onEmergencyTransportChanged(
        verify(mEmergencyStateTracker).onEmergencyTransportChangedAndWait(
                eq(EmergencyStateTracker.EMERGENCY_TYPE_CALL), eq(MODE_EMERGENCY_WWAN));

        wwanCallback.onDomainSelected(DOMAIN_CS, false);
@@ -222,7 +223,7 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest {
        IWwanSelectorCallback wwanCallback = onWwanSelected(mTransportCallback);

        assertFalse(future.isDone());
        verify(mEmergencyStateTracker).onEmergencyTransportChanged(
        verify(mEmergencyStateTracker).onEmergencyTransportChangedAndWait(
                eq(EmergencyStateTracker.EMERGENCY_TYPE_CALL), eq(MODE_EMERGENCY_WWAN));

        wwanCallback.onDomainSelected(DOMAIN_PS, true);
Loading