Loading src/java/com/android/internal/telephony/satellite/SatelliteController.java +132 −29 Original line number Diff line number Diff line Loading @@ -166,6 +166,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; Loading Loading @@ -200,7 +201,8 @@ public class SatelliteController extends Handler { public static final int TIMEOUT_TYPE_DEMO_POINTING_ALIGNED_DURATION_MILLIS = 2; /** This is used by CTS to override demo pointing not aligned duration. */ public static final int TIMEOUT_TYPE_DEMO_POINTING_NOT_ALIGNED_DURATION_MILLIS = 3; /** This is used by CTS to override evaluate esos profiles prioritization duration. */ public static final int TIMEOUT_TYPE_EVALUATE_ESOS_PROFILES_PRIORITIZATION_DURATION_MILLIS = 4; /** Key used to read/write OEM-enabled satellite provision status in shared preferences. */ private static final String OEM_ENABLED_SATELLITE_PROVISION_STATUS_KEY = "oem_enabled_satellite_provision_status_key"; Loading Loading @@ -521,7 +523,10 @@ public class SatelliteController extends Handler { // key : priority, low value is high, value : List<SubscriptionInfo> @GuardedBy("mSatelliteTokenProvisionedLock") @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected Map<Integer, List<SubscriptionInfo>> mSubsInfoListPerPriority = new HashMap<>(); protected TreeMap<Integer, List<SubscriptionInfo>> mSubsInfoListPerPriority = new TreeMap<>(); // The ID of the satellite subscription that has highest priority and is provisioned. @GuardedBy("mSatelliteTokenProvisionedLock") private int mSelectedSatelliteSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; // The last ICC ID that framework configured to modem. @GuardedBy("mSatelliteTokenProvisionedLock") private String mLastConfiguredIccId; Loading @@ -530,6 +535,7 @@ public class SatelliteController extends Handler { private long mWaitTimeForSatelliteEnablingResponse; private long mDemoPointingAlignedDurationMillis; private long mDemoPointingNotAlignedDurationMillis; private long mEvaluateEsosProfilesPrioritizationDurationMillis; private final Object mLock = new Object(); @GuardedBy("mLock") private long mLastEmergencyCallTime; Loading Loading @@ -720,8 +726,10 @@ public class SatelliteController extends Handler { getDemoPointingNotAlignedDurationMillisFromResources(); mSatelliteEmergencyModeDurationMillis = getSatelliteEmergencyModeDurationFromOverlayConfig(context); mEvaluateEsosProfilesPrioritizationDurationMillis = getEvaluateEsosProfilesPrioritizationDurationMillis(); sendMessageDelayed(obtainMessage(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION), /* delayMillis= */ TimeUnit.MINUTES.toMillis(1)); mEvaluateEsosProfilesPrioritizationDurationMillis); SubscriptionManager subscriptionManager = mContext.getSystemService( SubscriptionManager.class); Loading Loading @@ -1718,13 +1726,9 @@ public class SatelliteController extends Handler { RequestProvisionSatelliteArgument argument = (RequestProvisionSatelliteArgument) request.argument; onCompleted = obtainMessage(EVENT_UPDATE_PROVISION_SATELLITE_TOKEN_DONE, request); // only pass to index 0. // TODO: Select the subscription with highest priority and set it to mSatelliteSubId int subId = -1; synchronized (mSatelliteTokenProvisionedLock) { subId = mSubscriberIdPerSub.getOrDefault( argument.mSatelliteSubscriberInfoList.get(0).getSubscriberId(), -1); } boolean provisionChanged = updateSatelliteSubscriptionProvisionState( argument.mSatelliteSubscriberInfoList, argument.mProvisioned); int subId = getSelectedSatelliteSubId(); setSatellitePhone(subId); String iccId = mSubscriptionManagerService.getSubscriptionInfo(subId).getIccId(); argument.setIccId(iccId); Loading @@ -1738,13 +1742,16 @@ public class SatelliteController extends Handler { sendResponse = true; } } handleEventSatelliteSubscriptionProvisionStateChanged( argument.mSatelliteSubscriberInfoList, true); if (provisionChanged) { handleEventSatelliteSubscriptionProvisionStateChanged(); } if (sendResponse) { // The response is sent immediately because the ICCID has already been // delivered to the modem. Bundle bundle = new Bundle(); bundle.putBoolean(SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS, true); bundle.putBoolean( argument.mProvisioned ? SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS : SatelliteManager.KEY_DEPROVISION_SATELLITE_TOKENS, true); argument.mResult.send(SATELLITE_RESULT_SUCCESS, bundle); } break; Loading @@ -1764,7 +1771,9 @@ public class SatelliteController extends Handler { } logd("updateSatelliteSubscription result=" + error); Bundle bundle = new Bundle(); bundle.putBoolean(SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS, bundle.putBoolean( argument.mProvisioned ? SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS : SatelliteManager.KEY_DEPROVISION_SATELLITE_TOKENS, error == SATELLITE_RESULT_SUCCESS); argument.mResult.send(error, bundle); break; Loading Loading @@ -1829,11 +1838,13 @@ public class SatelliteController extends Handler { public ResultReceiver mResult; public long mRequestId; public String mIccId; public boolean mProvisioned; RequestProvisionSatelliteArgument(List<SatelliteSubscriberInfo> satelliteSubscriberInfoList, ResultReceiver result) { ResultReceiver result, boolean provisioned) { this.mSatelliteSubscriberInfoList = satelliteSubscriberInfoList; this.mResult = result; this.mProvisioned = provisioned; this.mRequestId = sNextSatelliteEnableRequestId.getAndUpdate( n -> ((n + 1) % Long.MAX_VALUE)); } Loading Loading @@ -3037,6 +3048,14 @@ public class SatelliteController extends Handler { } else { mDemoPointingNotAlignedDurationMillis = timeoutMillis; } } else if (timeoutType == TIMEOUT_TYPE_EVALUATE_ESOS_PROFILES_PRIORITIZATION_DURATION_MILLIS) { if (reset) { mEvaluateEsosProfilesPrioritizationDurationMillis = getEvaluateEsosProfilesPrioritizationDurationMillis(); } else { mEvaluateEsosProfilesPrioritizationDurationMillis = timeoutMillis; } } else { plogw("Invalid timeoutType=" + timeoutType); return false; Loading Loading @@ -3968,6 +3987,7 @@ public class SatelliteController extends Handler { }); } registerForSatelliteSupportedStateChanged(); selectBindingSatelliteSubscription(); } private void updateSatelliteEnabledState(boolean enabled, String caller) { Loading Loading @@ -4077,10 +4097,10 @@ public class SatelliteController extends Handler { }); } private void handleEventSatelliteSubscriptionProvisionStateChanged( List<SatelliteSubscriberInfo> newList, boolean provisioned) { logd("handleEventSatelliteSubscriptionProvisionStateChanged: newList=" + newList + " , provisioned=" + provisioned); private boolean updateSatelliteSubscriptionProvisionState(List<SatelliteSubscriberInfo> newList, boolean provisioned) { logd("updateSatelliteSubscriptionProvisionState: List=" + newList + " , provisioned=" + provisioned); boolean provisionChanged = false; synchronized (mSatelliteTokenProvisionedLock) { for (SatelliteSubscriberInfo subscriberInfo : newList) { Loading @@ -4095,19 +4115,18 @@ public class SatelliteController extends Handler { try { mSubscriptionManagerService.setIsSatelliteProvisionedForNonIpDatagram(subId, provisioned); plogd("handleEventSatelliteSubscriptionProvisionStateChanged: set Provision " + "state to db subId=" + subId); plogd("updateSatelliteSubscriptionProvisionState: set Provision state to db " + "subId=" + subId); } catch (IllegalArgumentException | SecurityException ex) { ploge("setIsSatelliteProvisionedForNonIpDatagram: subId=" + subId + ", ex=" + ex); } } } if (!provisionChanged) { logd("handleEventSatelliteSubscriptionProvisionStateChanged: provision state nothing " + "changed."); return; return provisionChanged; } private void handleEventSatelliteSubscriptionProvisionStateChanged() { List<SatelliteSubscriberProvisionStatus> informList = getPrioritizedSatelliteSubscriberProvisionStatusList(); plogd("handleEventSatelliteSubscriptionProvisionStateChanged: " + informList); Loading @@ -4118,6 +4137,7 @@ public class SatelliteController extends Handler { && mProvisionedSubscriberId.containsValue(Boolean.TRUE); mControllerMetricsStats.setIsProvisioned(isProvisioned); } selectBindingSatelliteSubscription(); handleStateChangedForCarrierRoamingNtnEligibility(); } Loading Loading @@ -4480,6 +4500,7 @@ public class SatelliteController extends Handler { updateSatelliteEnabledState( false, "moveSatelliteToOffStateAndCleanUpResources"); } selectBindingSatelliteSubscription(); } private void setDemoModeEnabled(boolean enabled) { Loading Loading @@ -6180,6 +6201,10 @@ public class SatelliteController extends Handler { return TimeUnit.SECONDS.toMillis(duration); } private long getEvaluateEsosProfilesPrioritizationDurationMillis() { return TimeUnit.MINUTES.toMillis(1); } /** * Calculate priority * 1. Active eSOS profiles are higher priority than inactive eSOS profiles. Loading @@ -6197,7 +6222,7 @@ public class SatelliteController extends Handler { List<SubscriptionInfo> allSubInfos = mSubscriptionManagerService.getAllSubInfoList( mContext.getOpPackageName(), mContext.getAttributionTag()); // Key : priority - lower value has higher priority; Value : List<SubscriptionInfo> Map<Integer, List<SubscriptionInfo>> newSubsInfoListPerPriority = new HashMap<>(); TreeMap<Integer, List<SubscriptionInfo>> newSubsInfoListPerPriority = new TreeMap<>(); synchronized (mSatelliteTokenProvisionedLock) { for (SubscriptionInfo info : allSubInfos) { int subId = info.getSubscriptionId(); Loading Loading @@ -6249,6 +6274,7 @@ public class SatelliteController extends Handler { mSubsInfoListPerPriority = newSubsInfoListPerPriority; sendBroadCastForProvisionedESOSSubs(); mHasSentBroadcast = true; selectBindingSatelliteSubscription(); } } } Loading Loading @@ -6408,6 +6434,57 @@ public class SatelliteController extends Handler { return list; } private int getSelectedSatelliteSubId() { synchronized (mSatelliteTokenProvisionedLock) { return mSelectedSatelliteSubId; } } private void selectBindingSatelliteSubscription() { if (isSatelliteEnabled() || isSatelliteBeingEnabled()) { plogd("selectBindingSatelliteSubscription: satellite subscription will be selected " + "once the satellite session ends"); return; } int selectedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; List<SatelliteSubscriberProvisionStatus> satelliteSubscribers = getPrioritizedSatelliteSubscriberProvisionStatusList(); for (SatelliteSubscriberProvisionStatus status : satelliteSubscribers) { // TODO: need to check if satellite is allowed at current location for the subscription int subId = getSubIdFromSubscriberId( status.getSatelliteSubscriberInfo().getSubscriberId()); if (status.getProvisionStatus() && isActiveSubId(subId)) { selectedSubId = subId; break; } } synchronized (mSatelliteTokenProvisionedLock) { if (selectedSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID && isSatelliteSupportedViaOem()) { mSelectedSatelliteSubId = SatelliteServiceUtils.getNtnOnlySubscriptionId(mContext); } if (selectedSubId != mSelectedSatelliteSubId) { mSelectedSatelliteSubId = selectedSubId; setSatellitePhone(selectedSubId); } } plogd("selectBindingSatelliteSubscription: SelectedSatelliteSubId=" + mSelectedSatelliteSubId); } private int getSubIdFromSubscriberId(String subscriberId) { synchronized (mSatelliteTokenProvisionedLock) { return mSubscriberIdPerSub.getOrDefault(subscriberId, SubscriptionManager.INVALID_SUBSCRIPTION_ID); } } private boolean isActiveSubId(int subId) { return mSubscriptionManagerService.getSubscriptionInfo(subId).isActive(); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected boolean isSubscriptionProvisioned(int subId) { plogd("isSubscriptionProvisioned: subId=" + subId); Loading Loading @@ -6438,19 +6515,45 @@ public class SatelliteController extends Handler { @NonNull ResultReceiver result) { if (!mFeatureFlags.carrierRoamingNbIotNtn()) { result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null); logd("provisionSatellite: carrierRoamingNbIotNtn not support"); return; } if (list.size() == 0) { if (list.isEmpty()) { result.send(SATELLITE_RESULT_INVALID_ARGUMENTS, null); logd("provisionSatellite: SatelliteSubscriberInfo list is empty"); return; } logd("provisionSatellite:" + list); RequestProvisionSatelliteArgument request = new RequestProvisionSatelliteArgument(list, result); result, true); sendRequestAsync(CMD_UPDATE_PROVISION_SATELLITE_TOKEN, request, null); } /** * Deliver the list of deprovisioned satellite subscriber ids. * * @param list List of deprovisioned satellite subscriber ids. * @param result The result receiver that returns whether deliver success or fail. */ public void deprovisionSatellite(@NonNull List<SatelliteSubscriberInfo> list, @NonNull ResultReceiver result) { if (!mFeatureFlags.carrierRoamingNbIotNtn()) { result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null); logd("deprovisionSatellite: carrierRoamingNbIotNtn not support"); return; } if (list.isEmpty()) { result.send(SATELLITE_RESULT_INVALID_ARGUMENTS, null); logd("deprovisionSatellite: SatelliteSubscriberInfo list is empty"); return; } logd("deprovisionSatellite:" + list); RequestProvisionSatelliteArgument request = new RequestProvisionSatelliteArgument(list, result, false); sendRequestAsync(CMD_UPDATE_PROVISION_SATELLITE_TOKEN, request, null); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected void setSatellitePhone(int subId) { Loading tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java +85 −5 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_ import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_NONE; import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_POOR; import static android.telephony.satellite.SatelliteManager.KEY_DEMO_MODE_ENABLED; import static android.telephony.satellite.SatelliteManager.KEY_DEPROVISION_SATELLITE_TOKENS; import static android.telephony.satellite.SatelliteManager.KEY_EMERGENCY_MODE_ENABLED; import static android.telephony.satellite.SatelliteManager.KEY_NTN_SIGNAL_STRENGTH; import static android.telephony.satellite.SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS; Loading Loading @@ -4346,7 +4347,6 @@ public class SatelliteControllerTest extends TelephonyTest { assertTrue(mProvisionState); } @Test public void testRegisterForSatelliteSubscriptionProvisionStateChanged() throws Exception { when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true); Loading Loading @@ -4405,8 +4405,6 @@ public class SatelliteControllerTest extends TelephonyTest { inputList.add(list.get(1)); verifyProvisionSatellite(inputList); verify(mMockSatelliteModemInterface, times(2)).updateSatelliteSubscription(anyString(), any()); assertTrue(waitForForEvents( semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged")); assertTrue(resultArray[1].getProvisionStatus()); Loading @@ -4416,10 +4414,92 @@ public class SatelliteControllerTest extends TelephonyTest { // requested, and verify that onSatelliteSubscriptionProvisionStateChanged is not called. verifyProvisionSatellite(inputList); verify(mMockSatelliteModemInterface, times(2)).updateSatelliteSubscription(anyString(), any()); assertFalse(waitForForEvents( semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged")); // Request deprovision for subscriberID 2, verify that subscriberID 2 is set to // deprovision and that subscriberID 1 is set to provision. verifyDeprovisionSatellite(inputList); assertTrue(waitForForEvents( semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged")); assertFalse(resultArray[1].getProvisionStatus()); assertEquals(mSubscriberId2, resultArray[1].getSatelliteSubscriberInfo().getSubscriberId()); assertTrue(resultArray[0].getProvisionStatus()); assertEquals(mSubscriberId, resultArray[0].getSatelliteSubscriberInfo().getSubscriberId()); // Request deprovision for subscriberID 1, verify that subscriberID 1 is set to deprovision. inputList = new ArrayList<>(); inputList.add(list.get(0)); verifyDeprovisionSatellite(inputList); assertTrue(waitForForEvents( semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged")); assertFalse(resultArray[1].getProvisionStatus()); assertEquals(mSubscriberId2, resultArray[1].getSatelliteSubscriberInfo().getSubscriberId()); assertFalse(resultArray[0].getProvisionStatus()); assertEquals(mSubscriberId, resultArray[0].getSatelliteSubscriberInfo().getSubscriberId()); // Request provision for subscriberID 2, verify that subscriberID 2 is set to provision. inputList = new ArrayList<>(); inputList.add(list.get(1)); verifyProvisionSatellite(inputList); assertTrue(waitForForEvents( semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged")); assertTrue(resultArray[1].getProvisionStatus()); assertEquals(mSubscriberId2, resultArray[1].getSatelliteSubscriberInfo().getSubscriberId()); assertFalse(resultArray[0].getProvisionStatus()); assertEquals(mSubscriberId, resultArray[0].getSatelliteSubscriberInfo().getSubscriberId()); } private boolean mDeprovisionDone = false; private int mDeprovisionSateResultCode = -1; private Semaphore mDeprovisionSateSemaphore = new Semaphore(0); private ResultReceiver mDeprovisionSatelliteReceiver = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { mDeprovisionSateResultCode = resultCode; logd("DeprovisionSatelliteReceiver: resultCode=" + resultCode); if (resultCode == SATELLITE_RESULT_SUCCESS) { if (resultData.containsKey(KEY_DEPROVISION_SATELLITE_TOKENS)) { mDeprovisionDone = resultData.getBoolean(KEY_DEPROVISION_SATELLITE_TOKENS); logd("DeprovisionSatelliteReceiver: deprovision=" + mDeprovisionDone); } else { loge("KEY_DEPROVISION_SATELLITE_TOKENS does not exist."); mDeprovisionDone = false; } } else { mDeprovisionDone = false; } try { mDeprovisionSateSemaphore.release(); } catch (Exception ex) { loge("DeprovisionSatelliteReceiver: Got exception in releasing semaphore " + ex); } } }; @Test public void testDeprovisionSatellite() throws Exception { when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true); when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); verifyRequestSatelliteSubscriberProvisionStatus(); List<SatelliteSubscriberInfo> inputList = getExpectedSatelliteSubscriberInfoList(); verifyProvisionSatellite(inputList); verifyDeprovisionSatellite(inputList); } private void verifyDeprovisionSatellite(List<SatelliteSubscriberInfo> inputList) { doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[1]; AsyncResult.forMessage(message, null, new SatelliteException(SATELLITE_RESULT_SUCCESS)); message.sendToTarget(); return null; }).when(mMockSatelliteModemInterface).updateSatelliteSubscription(anyString(), any()); mSatelliteControllerUT.deprovisionSatellite(inputList, mDeprovisionSatelliteReceiver); processAllMessages(); assertEquals(SATELLITE_RESULT_SUCCESS, mDeprovisionSateResultCode); assertTrue(mDeprovisionDone); } private void setSatelliteSubscriberTesting() throws Exception { Loading Loading
src/java/com/android/internal/telephony/satellite/SatelliteController.java +132 −29 Original line number Diff line number Diff line Loading @@ -166,6 +166,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; Loading Loading @@ -200,7 +201,8 @@ public class SatelliteController extends Handler { public static final int TIMEOUT_TYPE_DEMO_POINTING_ALIGNED_DURATION_MILLIS = 2; /** This is used by CTS to override demo pointing not aligned duration. */ public static final int TIMEOUT_TYPE_DEMO_POINTING_NOT_ALIGNED_DURATION_MILLIS = 3; /** This is used by CTS to override evaluate esos profiles prioritization duration. */ public static final int TIMEOUT_TYPE_EVALUATE_ESOS_PROFILES_PRIORITIZATION_DURATION_MILLIS = 4; /** Key used to read/write OEM-enabled satellite provision status in shared preferences. */ private static final String OEM_ENABLED_SATELLITE_PROVISION_STATUS_KEY = "oem_enabled_satellite_provision_status_key"; Loading Loading @@ -521,7 +523,10 @@ public class SatelliteController extends Handler { // key : priority, low value is high, value : List<SubscriptionInfo> @GuardedBy("mSatelliteTokenProvisionedLock") @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected Map<Integer, List<SubscriptionInfo>> mSubsInfoListPerPriority = new HashMap<>(); protected TreeMap<Integer, List<SubscriptionInfo>> mSubsInfoListPerPriority = new TreeMap<>(); // The ID of the satellite subscription that has highest priority and is provisioned. @GuardedBy("mSatelliteTokenProvisionedLock") private int mSelectedSatelliteSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; // The last ICC ID that framework configured to modem. @GuardedBy("mSatelliteTokenProvisionedLock") private String mLastConfiguredIccId; Loading @@ -530,6 +535,7 @@ public class SatelliteController extends Handler { private long mWaitTimeForSatelliteEnablingResponse; private long mDemoPointingAlignedDurationMillis; private long mDemoPointingNotAlignedDurationMillis; private long mEvaluateEsosProfilesPrioritizationDurationMillis; private final Object mLock = new Object(); @GuardedBy("mLock") private long mLastEmergencyCallTime; Loading Loading @@ -720,8 +726,10 @@ public class SatelliteController extends Handler { getDemoPointingNotAlignedDurationMillisFromResources(); mSatelliteEmergencyModeDurationMillis = getSatelliteEmergencyModeDurationFromOverlayConfig(context); mEvaluateEsosProfilesPrioritizationDurationMillis = getEvaluateEsosProfilesPrioritizationDurationMillis(); sendMessageDelayed(obtainMessage(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION), /* delayMillis= */ TimeUnit.MINUTES.toMillis(1)); mEvaluateEsosProfilesPrioritizationDurationMillis); SubscriptionManager subscriptionManager = mContext.getSystemService( SubscriptionManager.class); Loading Loading @@ -1718,13 +1726,9 @@ public class SatelliteController extends Handler { RequestProvisionSatelliteArgument argument = (RequestProvisionSatelliteArgument) request.argument; onCompleted = obtainMessage(EVENT_UPDATE_PROVISION_SATELLITE_TOKEN_DONE, request); // only pass to index 0. // TODO: Select the subscription with highest priority and set it to mSatelliteSubId int subId = -1; synchronized (mSatelliteTokenProvisionedLock) { subId = mSubscriberIdPerSub.getOrDefault( argument.mSatelliteSubscriberInfoList.get(0).getSubscriberId(), -1); } boolean provisionChanged = updateSatelliteSubscriptionProvisionState( argument.mSatelliteSubscriberInfoList, argument.mProvisioned); int subId = getSelectedSatelliteSubId(); setSatellitePhone(subId); String iccId = mSubscriptionManagerService.getSubscriptionInfo(subId).getIccId(); argument.setIccId(iccId); Loading @@ -1738,13 +1742,16 @@ public class SatelliteController extends Handler { sendResponse = true; } } handleEventSatelliteSubscriptionProvisionStateChanged( argument.mSatelliteSubscriberInfoList, true); if (provisionChanged) { handleEventSatelliteSubscriptionProvisionStateChanged(); } if (sendResponse) { // The response is sent immediately because the ICCID has already been // delivered to the modem. Bundle bundle = new Bundle(); bundle.putBoolean(SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS, true); bundle.putBoolean( argument.mProvisioned ? SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS : SatelliteManager.KEY_DEPROVISION_SATELLITE_TOKENS, true); argument.mResult.send(SATELLITE_RESULT_SUCCESS, bundle); } break; Loading @@ -1764,7 +1771,9 @@ public class SatelliteController extends Handler { } logd("updateSatelliteSubscription result=" + error); Bundle bundle = new Bundle(); bundle.putBoolean(SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS, bundle.putBoolean( argument.mProvisioned ? SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS : SatelliteManager.KEY_DEPROVISION_SATELLITE_TOKENS, error == SATELLITE_RESULT_SUCCESS); argument.mResult.send(error, bundle); break; Loading Loading @@ -1829,11 +1838,13 @@ public class SatelliteController extends Handler { public ResultReceiver mResult; public long mRequestId; public String mIccId; public boolean mProvisioned; RequestProvisionSatelliteArgument(List<SatelliteSubscriberInfo> satelliteSubscriberInfoList, ResultReceiver result) { ResultReceiver result, boolean provisioned) { this.mSatelliteSubscriberInfoList = satelliteSubscriberInfoList; this.mResult = result; this.mProvisioned = provisioned; this.mRequestId = sNextSatelliteEnableRequestId.getAndUpdate( n -> ((n + 1) % Long.MAX_VALUE)); } Loading Loading @@ -3037,6 +3048,14 @@ public class SatelliteController extends Handler { } else { mDemoPointingNotAlignedDurationMillis = timeoutMillis; } } else if (timeoutType == TIMEOUT_TYPE_EVALUATE_ESOS_PROFILES_PRIORITIZATION_DURATION_MILLIS) { if (reset) { mEvaluateEsosProfilesPrioritizationDurationMillis = getEvaluateEsosProfilesPrioritizationDurationMillis(); } else { mEvaluateEsosProfilesPrioritizationDurationMillis = timeoutMillis; } } else { plogw("Invalid timeoutType=" + timeoutType); return false; Loading Loading @@ -3968,6 +3987,7 @@ public class SatelliteController extends Handler { }); } registerForSatelliteSupportedStateChanged(); selectBindingSatelliteSubscription(); } private void updateSatelliteEnabledState(boolean enabled, String caller) { Loading Loading @@ -4077,10 +4097,10 @@ public class SatelliteController extends Handler { }); } private void handleEventSatelliteSubscriptionProvisionStateChanged( List<SatelliteSubscriberInfo> newList, boolean provisioned) { logd("handleEventSatelliteSubscriptionProvisionStateChanged: newList=" + newList + " , provisioned=" + provisioned); private boolean updateSatelliteSubscriptionProvisionState(List<SatelliteSubscriberInfo> newList, boolean provisioned) { logd("updateSatelliteSubscriptionProvisionState: List=" + newList + " , provisioned=" + provisioned); boolean provisionChanged = false; synchronized (mSatelliteTokenProvisionedLock) { for (SatelliteSubscriberInfo subscriberInfo : newList) { Loading @@ -4095,19 +4115,18 @@ public class SatelliteController extends Handler { try { mSubscriptionManagerService.setIsSatelliteProvisionedForNonIpDatagram(subId, provisioned); plogd("handleEventSatelliteSubscriptionProvisionStateChanged: set Provision " + "state to db subId=" + subId); plogd("updateSatelliteSubscriptionProvisionState: set Provision state to db " + "subId=" + subId); } catch (IllegalArgumentException | SecurityException ex) { ploge("setIsSatelliteProvisionedForNonIpDatagram: subId=" + subId + ", ex=" + ex); } } } if (!provisionChanged) { logd("handleEventSatelliteSubscriptionProvisionStateChanged: provision state nothing " + "changed."); return; return provisionChanged; } private void handleEventSatelliteSubscriptionProvisionStateChanged() { List<SatelliteSubscriberProvisionStatus> informList = getPrioritizedSatelliteSubscriberProvisionStatusList(); plogd("handleEventSatelliteSubscriptionProvisionStateChanged: " + informList); Loading @@ -4118,6 +4137,7 @@ public class SatelliteController extends Handler { && mProvisionedSubscriberId.containsValue(Boolean.TRUE); mControllerMetricsStats.setIsProvisioned(isProvisioned); } selectBindingSatelliteSubscription(); handleStateChangedForCarrierRoamingNtnEligibility(); } Loading Loading @@ -4480,6 +4500,7 @@ public class SatelliteController extends Handler { updateSatelliteEnabledState( false, "moveSatelliteToOffStateAndCleanUpResources"); } selectBindingSatelliteSubscription(); } private void setDemoModeEnabled(boolean enabled) { Loading Loading @@ -6180,6 +6201,10 @@ public class SatelliteController extends Handler { return TimeUnit.SECONDS.toMillis(duration); } private long getEvaluateEsosProfilesPrioritizationDurationMillis() { return TimeUnit.MINUTES.toMillis(1); } /** * Calculate priority * 1. Active eSOS profiles are higher priority than inactive eSOS profiles. Loading @@ -6197,7 +6222,7 @@ public class SatelliteController extends Handler { List<SubscriptionInfo> allSubInfos = mSubscriptionManagerService.getAllSubInfoList( mContext.getOpPackageName(), mContext.getAttributionTag()); // Key : priority - lower value has higher priority; Value : List<SubscriptionInfo> Map<Integer, List<SubscriptionInfo>> newSubsInfoListPerPriority = new HashMap<>(); TreeMap<Integer, List<SubscriptionInfo>> newSubsInfoListPerPriority = new TreeMap<>(); synchronized (mSatelliteTokenProvisionedLock) { for (SubscriptionInfo info : allSubInfos) { int subId = info.getSubscriptionId(); Loading Loading @@ -6249,6 +6274,7 @@ public class SatelliteController extends Handler { mSubsInfoListPerPriority = newSubsInfoListPerPriority; sendBroadCastForProvisionedESOSSubs(); mHasSentBroadcast = true; selectBindingSatelliteSubscription(); } } } Loading Loading @@ -6408,6 +6434,57 @@ public class SatelliteController extends Handler { return list; } private int getSelectedSatelliteSubId() { synchronized (mSatelliteTokenProvisionedLock) { return mSelectedSatelliteSubId; } } private void selectBindingSatelliteSubscription() { if (isSatelliteEnabled() || isSatelliteBeingEnabled()) { plogd("selectBindingSatelliteSubscription: satellite subscription will be selected " + "once the satellite session ends"); return; } int selectedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; List<SatelliteSubscriberProvisionStatus> satelliteSubscribers = getPrioritizedSatelliteSubscriberProvisionStatusList(); for (SatelliteSubscriberProvisionStatus status : satelliteSubscribers) { // TODO: need to check if satellite is allowed at current location for the subscription int subId = getSubIdFromSubscriberId( status.getSatelliteSubscriberInfo().getSubscriberId()); if (status.getProvisionStatus() && isActiveSubId(subId)) { selectedSubId = subId; break; } } synchronized (mSatelliteTokenProvisionedLock) { if (selectedSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID && isSatelliteSupportedViaOem()) { mSelectedSatelliteSubId = SatelliteServiceUtils.getNtnOnlySubscriptionId(mContext); } if (selectedSubId != mSelectedSatelliteSubId) { mSelectedSatelliteSubId = selectedSubId; setSatellitePhone(selectedSubId); } } plogd("selectBindingSatelliteSubscription: SelectedSatelliteSubId=" + mSelectedSatelliteSubId); } private int getSubIdFromSubscriberId(String subscriberId) { synchronized (mSatelliteTokenProvisionedLock) { return mSubscriberIdPerSub.getOrDefault(subscriberId, SubscriptionManager.INVALID_SUBSCRIPTION_ID); } } private boolean isActiveSubId(int subId) { return mSubscriptionManagerService.getSubscriptionInfo(subId).isActive(); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected boolean isSubscriptionProvisioned(int subId) { plogd("isSubscriptionProvisioned: subId=" + subId); Loading Loading @@ -6438,19 +6515,45 @@ public class SatelliteController extends Handler { @NonNull ResultReceiver result) { if (!mFeatureFlags.carrierRoamingNbIotNtn()) { result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null); logd("provisionSatellite: carrierRoamingNbIotNtn not support"); return; } if (list.size() == 0) { if (list.isEmpty()) { result.send(SATELLITE_RESULT_INVALID_ARGUMENTS, null); logd("provisionSatellite: SatelliteSubscriberInfo list is empty"); return; } logd("provisionSatellite:" + list); RequestProvisionSatelliteArgument request = new RequestProvisionSatelliteArgument(list, result); result, true); sendRequestAsync(CMD_UPDATE_PROVISION_SATELLITE_TOKEN, request, null); } /** * Deliver the list of deprovisioned satellite subscriber ids. * * @param list List of deprovisioned satellite subscriber ids. * @param result The result receiver that returns whether deliver success or fail. */ public void deprovisionSatellite(@NonNull List<SatelliteSubscriberInfo> list, @NonNull ResultReceiver result) { if (!mFeatureFlags.carrierRoamingNbIotNtn()) { result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null); logd("deprovisionSatellite: carrierRoamingNbIotNtn not support"); return; } if (list.isEmpty()) { result.send(SATELLITE_RESULT_INVALID_ARGUMENTS, null); logd("deprovisionSatellite: SatelliteSubscriberInfo list is empty"); return; } logd("deprovisionSatellite:" + list); RequestProvisionSatelliteArgument request = new RequestProvisionSatelliteArgument(list, result, false); sendRequestAsync(CMD_UPDATE_PROVISION_SATELLITE_TOKEN, request, null); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected void setSatellitePhone(int subId) { Loading
tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java +85 −5 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_ import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_NONE; import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_POOR; import static android.telephony.satellite.SatelliteManager.KEY_DEMO_MODE_ENABLED; import static android.telephony.satellite.SatelliteManager.KEY_DEPROVISION_SATELLITE_TOKENS; import static android.telephony.satellite.SatelliteManager.KEY_EMERGENCY_MODE_ENABLED; import static android.telephony.satellite.SatelliteManager.KEY_NTN_SIGNAL_STRENGTH; import static android.telephony.satellite.SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS; Loading Loading @@ -4346,7 +4347,6 @@ public class SatelliteControllerTest extends TelephonyTest { assertTrue(mProvisionState); } @Test public void testRegisterForSatelliteSubscriptionProvisionStateChanged() throws Exception { when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true); Loading Loading @@ -4405,8 +4405,6 @@ public class SatelliteControllerTest extends TelephonyTest { inputList.add(list.get(1)); verifyProvisionSatellite(inputList); verify(mMockSatelliteModemInterface, times(2)).updateSatelliteSubscription(anyString(), any()); assertTrue(waitForForEvents( semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged")); assertTrue(resultArray[1].getProvisionStatus()); Loading @@ -4416,10 +4414,92 @@ public class SatelliteControllerTest extends TelephonyTest { // requested, and verify that onSatelliteSubscriptionProvisionStateChanged is not called. verifyProvisionSatellite(inputList); verify(mMockSatelliteModemInterface, times(2)).updateSatelliteSubscription(anyString(), any()); assertFalse(waitForForEvents( semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged")); // Request deprovision for subscriberID 2, verify that subscriberID 2 is set to // deprovision and that subscriberID 1 is set to provision. verifyDeprovisionSatellite(inputList); assertTrue(waitForForEvents( semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged")); assertFalse(resultArray[1].getProvisionStatus()); assertEquals(mSubscriberId2, resultArray[1].getSatelliteSubscriberInfo().getSubscriberId()); assertTrue(resultArray[0].getProvisionStatus()); assertEquals(mSubscriberId, resultArray[0].getSatelliteSubscriberInfo().getSubscriberId()); // Request deprovision for subscriberID 1, verify that subscriberID 1 is set to deprovision. inputList = new ArrayList<>(); inputList.add(list.get(0)); verifyDeprovisionSatellite(inputList); assertTrue(waitForForEvents( semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged")); assertFalse(resultArray[1].getProvisionStatus()); assertEquals(mSubscriberId2, resultArray[1].getSatelliteSubscriberInfo().getSubscriberId()); assertFalse(resultArray[0].getProvisionStatus()); assertEquals(mSubscriberId, resultArray[0].getSatelliteSubscriberInfo().getSubscriberId()); // Request provision for subscriberID 2, verify that subscriberID 2 is set to provision. inputList = new ArrayList<>(); inputList.add(list.get(1)); verifyProvisionSatellite(inputList); assertTrue(waitForForEvents( semaphore, 1, "testRegisterForSatelliteSubscriptionProvisionStateChanged")); assertTrue(resultArray[1].getProvisionStatus()); assertEquals(mSubscriberId2, resultArray[1].getSatelliteSubscriberInfo().getSubscriberId()); assertFalse(resultArray[0].getProvisionStatus()); assertEquals(mSubscriberId, resultArray[0].getSatelliteSubscriberInfo().getSubscriberId()); } private boolean mDeprovisionDone = false; private int mDeprovisionSateResultCode = -1; private Semaphore mDeprovisionSateSemaphore = new Semaphore(0); private ResultReceiver mDeprovisionSatelliteReceiver = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { mDeprovisionSateResultCode = resultCode; logd("DeprovisionSatelliteReceiver: resultCode=" + resultCode); if (resultCode == SATELLITE_RESULT_SUCCESS) { if (resultData.containsKey(KEY_DEPROVISION_SATELLITE_TOKENS)) { mDeprovisionDone = resultData.getBoolean(KEY_DEPROVISION_SATELLITE_TOKENS); logd("DeprovisionSatelliteReceiver: deprovision=" + mDeprovisionDone); } else { loge("KEY_DEPROVISION_SATELLITE_TOKENS does not exist."); mDeprovisionDone = false; } } else { mDeprovisionDone = false; } try { mDeprovisionSateSemaphore.release(); } catch (Exception ex) { loge("DeprovisionSatelliteReceiver: Got exception in releasing semaphore " + ex); } } }; @Test public void testDeprovisionSatellite() throws Exception { when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true); when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); verifyRequestSatelliteSubscriberProvisionStatus(); List<SatelliteSubscriberInfo> inputList = getExpectedSatelliteSubscriberInfoList(); verifyProvisionSatellite(inputList); verifyDeprovisionSatellite(inputList); } private void verifyDeprovisionSatellite(List<SatelliteSubscriberInfo> inputList) { doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[1]; AsyncResult.forMessage(message, null, new SatelliteException(SATELLITE_RESULT_SUCCESS)); message.sendToTarget(); return null; }).when(mMockSatelliteModemInterface).updateSatelliteSubscription(anyString(), any()); mSatelliteControllerUT.deprovisionSatellite(inputList, mDeprovisionSatelliteReceiver); processAllMessages(); assertEquals(SATELLITE_RESULT_SUCCESS, mDeprovisionSateResultCode); assertTrue(mDeprovisionDone); } private void setSatelliteSubscriberTesting() throws Exception { Loading