Loading src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java +46 −18 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -156,8 +174,6 @@ public class DomainSelectionConnection { waitForServiceBinding(null); } } }); } } @Override Loading Loading @@ -333,6 +349,8 @@ public class DomainSelectionConnection { private @Nullable ScanRequest mPendingScanRequest; private boolean mIsTestMode = false; /** * Creates an instance. * Loading Loading @@ -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. */ Loading src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java +1 −1 Original line number Diff line number Diff line Loading @@ -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); } Loading src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +76 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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_", Loading Loading @@ -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 = Loading Loading @@ -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); Loading Loading @@ -600,6 +608,9 @@ public class EmergencyStateTracker { clearEmergencyCallInfo(); } } // Release any blocked thread immediately maybeNotifyTransportChangeCompleted(EMERGENCY_TYPE_CALL, true); } private void clearEmergencyCallInfo() { Loading Loading @@ -643,6 +654,8 @@ public class EmergencyStateTracker { + emergencyTypeToString(emergencyType)); if (mEmergencyMode == mode) { // Initial transport selection of DomainSelector maybeNotifyTransportChangeCompleted(emergencyType, false); return; } mEmergencyMode = mode; Loading Loading @@ -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. * Loading tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java +1 −0 Original line number Diff line number Diff line Loading @@ -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; Loading tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java +3 −2 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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); Loading Loading @@ -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 Loading
src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java +46 −18 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -156,8 +174,6 @@ public class DomainSelectionConnection { waitForServiceBinding(null); } } }); } } @Override Loading Loading @@ -333,6 +349,8 @@ public class DomainSelectionConnection { private @Nullable ScanRequest mPendingScanRequest; private boolean mIsTestMode = false; /** * Creates an instance. * Loading Loading @@ -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. */ Loading
src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java +1 −1 Original line number Diff line number Diff line Loading @@ -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); } Loading
src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +76 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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_", Loading Loading @@ -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 = Loading Loading @@ -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); Loading Loading @@ -600,6 +608,9 @@ public class EmergencyStateTracker { clearEmergencyCallInfo(); } } // Release any blocked thread immediately maybeNotifyTransportChangeCompleted(EMERGENCY_TYPE_CALL, true); } private void clearEmergencyCallInfo() { Loading Loading @@ -643,6 +654,8 @@ public class EmergencyStateTracker { + emergencyTypeToString(emergencyType)); if (mEmergencyMode == mode) { // Initial transport selection of DomainSelector maybeNotifyTransportChangeCompleted(emergencyType, false); return; } mEmergencyMode = mode; Loading Loading @@ -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. * Loading
tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java +1 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java +3 −2 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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); Loading Loading @@ -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