Use the new HAL API updateSystemSelectionChannels to pass the bands/frequency to vendor service.

Bug: 371438496
Flag: com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn
Test: atest SatelliteAccessControllerTest SatelliteControllerTest
Test: manually run e2e system test for checking functionality and
regression

Change-Id: I99404ee6adb464979f0f1d701a952134f6c83363
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index a47691e..251ba65 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -25,6 +25,7 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_ACCESS_BARRED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_DISABLED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_NOT_AVAILABLE;
@@ -80,11 +81,13 @@
 import android.telephony.Rlog;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
+import android.telephony.satellite.EarfcnRange;
 import android.telephony.satellite.ISatelliteCommunicationAllowedStateCallback;
 import android.telephony.satellite.ISatelliteDisallowedReasonsCallback;
 import android.telephony.satellite.ISatelliteProvisionStateCallback;
 import android.telephony.satellite.ISatelliteSupportedStateCallback;
 import android.telephony.satellite.SatelliteAccessConfiguration;
+import android.telephony.satellite.SatelliteInfo;
 import android.telephony.satellite.SatelliteManager;
 import android.telephony.satellite.SatelliteSubscriberProvisionStatus;
 import android.telephony.satellite.SystemSelectionSpecifier;
@@ -133,6 +136,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 /**
  * This module is responsible for making sure that satellite communication can be used by devices
@@ -321,7 +325,8 @@
     /** Key: Config ID; Value: SatelliteAccessConfiguration */
     @GuardedBy("mLock")
     @Nullable
-    private Map<Integer, SatelliteAccessConfiguration> mSatelliteAccessConfigMap;
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    protected Map<Integer, SatelliteAccessConfiguration> mSatelliteAccessConfigMap;
 
     /** These are used for CTS test */
     private Path mCtsSatS2FilePath = null;
@@ -358,6 +363,7 @@
     protected static final int
             DEFAULT_MAX_RETRY_COUNT_FOR_VALIDATING_POSSIBLE_CHANGE_IN_ALLOWED_REGION = 3;
     protected static final int DEFAULT_THROTTLE_INTERVAL_FOR_LOCATION_QUERY_MINUTES = 10;
+    private static final int MAX_EARFCN_ARRAY_LENGTH = 32;
 
     private long mRetryIntervalToEvaluateUserInSatelliteAllowedRegion = 0;
     private int mMaxRetryCountForValidatingPossibleChangeInAllowedRegion = 0;
@@ -808,7 +814,7 @@
             if (mRegionalConfigId == null) {
                 plogd("updateSystemSelectionChannels: Invalid Regional config ID."
                         + " System Selection channels can not be passed down to modem");
-                result.send(SatelliteManager.SATELLITE_RESULT_ACCESS_BARRED, null);
+                result.send(SATELLITE_RESULT_ACCESS_BARRED, null);
                 return;
             }
         }
@@ -2224,41 +2230,66 @@
                 mccmnc = subInfo.getMccString() + subInfo.getMncString();
             }
 
-            synchronized (mRegionalSatelliteEarfcnsLock) {
-                /* Key: Regional satellite config ID, Value: SatelliteRegionalConfig
-                 * contains satellite config IDs and set of earfcns in the corresponding regions.
-                 */
-                Map<Integer, SatelliteRegionalConfig> satelliteRegionalConfigMap =
-                        mSatelliteRegionalConfigPerSubMap.get(subId);
-                if (satelliteRegionalConfigMap == null || satelliteRegionalConfigMap.isEmpty()) {
-                    plogd("handleCmdUpdateSystemSelectionChannels: config IDs and Earfcns are not"
-                            + " found for subId: "
-                            + subId);
-                    sendUpdateSystemSelectionChannelsResult(
-                            SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-                    return;
-                }
-
-                SatelliteRegionalConfig satelliteRegionalConfig = satelliteRegionalConfigMap.get(
-                        mRegionalConfigId);
-                if (satelliteRegionalConfig == null) {
-                    plogd("handleCmdUpdateSystemSelectionChannels: "
-                            + "Earfcns for satellite config Id: " + mRegionalConfigId
-                            + " not found");
-                    sendUpdateSystemSelectionChannelsResult(
-                            SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-                    return;
-                }
-                IntArray bands = new IntArray();
-                IntArray earfcns = new IntArray();
-                for (Integer value : satelliteRegionalConfig.getEarfcns()) {
-                    earfcns.add(value);
-                }
-
-                mSatelliteController.updateSystemSelectionChannels(
-                        new SystemSelectionSpecifier(mccmnc, bands, earfcns),
-                        mInternalUpdateSystemSelectionChannelsResultReceiver);
+            final Integer[] regionalConfigId = new Integer[1];
+            regionalConfigId[0] = getSelectedRegionalConfigId();
+            if (regionalConfigId[0] != null
+                    && regionalConfigId[0] == UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID) {
+                // The geofence file with old format return UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID
+                // for an S2 cell present in the file.
+                // For backward compatibility, we will use DEFAULT_REGIONAL_SATELLITE_CONFIG_ID
+                // for such cases.
+                regionalConfigId[0] = DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
             }
+            if (!SatelliteAccessConfigurationParser.isRegionalConfigIdValid(regionalConfigId[0])) {
+                plogd("handleCmdUpdateSystemSelectionChannels: mRegionalConfigId is not valid, "
+                        + "mRegionalConfig=" + getSelectedRegionalConfigId());
+                sendUpdateSystemSelectionChannelsResult(
+                        SATELLITE_RESULT_ACCESS_BARRED, null);
+                return;
+            }
+
+            SatelliteAccessConfiguration satelliteAccessConfiguration;
+            synchronized (mLock) {
+                satelliteAccessConfiguration = Optional.ofNullable(mSatelliteAccessConfigMap)
+                        .map(map -> map.get(regionalConfigId[0]))
+                        .orElse(null);
+            }
+            if (satelliteAccessConfiguration == null) {
+                plogd("handleCmdUpdateSystemSelectionChannels: satelliteAccessConfiguration "
+                        + "is not valid");
+                sendUpdateSystemSelectionChannelsResult(
+                        SATELLITE_RESULT_ACCESS_BARRED, null);
+                return;
+            }
+
+            List<SatelliteInfo> satelliteInfos =
+                    satelliteAccessConfiguration.getSatelliteInfos();
+            List<Integer> bandList = new ArrayList<>();
+            List<Integer> earfcnList = new ArrayList<>();
+            for (SatelliteInfo satelliteInfo : satelliteInfos) {
+                bandList.addAll(satelliteInfo.getBands());
+                List<EarfcnRange> earfcnRangeList = satelliteInfo.getEarfcnRanges();
+                earfcnRangeList.stream().flatMapToInt(
+                        earfcnRange -> IntStream.of(earfcnRange.getStartEarfcn(),
+                                earfcnRange.getEndEarfcn())).boxed().forEach(earfcnList::add);
+            }
+
+            IntArray bands = new IntArray(bandList.size());
+            bands.addAll(bandList.stream().mapToInt(Integer::intValue).toArray());
+            IntArray earfcns = new IntArray(
+                    Math.min(earfcnList.size(), MAX_EARFCN_ARRAY_LENGTH));
+            for (int i = 0; i < Math.min(earfcnList.size(), MAX_EARFCN_ARRAY_LENGTH); i++) {
+                earfcns.add(earfcnList.get(i));
+            }
+            IntArray tagIds = new IntArray(satelliteAccessConfiguration.getTagIds().size());
+            tagIds.addAll(satelliteAccessConfiguration.getTagIds().stream().mapToInt(
+                    Integer::intValue).toArray());
+
+            List<SystemSelectionSpecifier> selectionSpecifiers = new ArrayList<>();
+            selectionSpecifiers.add(new SystemSelectionSpecifier(mccmnc, bands, earfcns,
+                    satelliteInfos.toArray(new SatelliteInfo[0]), tagIds));
+            mSatelliteController.updateSystemSelectionChannels(selectionSpecifiers,
+                    mInternalUpdateSystemSelectionChannelsResultReceiver);
         }
     }
 
@@ -2909,6 +2940,13 @@
         evaluatePossibleChangeInDefaultSmsApp(context);
     }
 
+    @Nullable
+    private Integer getSelectedRegionalConfigId() {
+        synchronized (mLock) {
+            return mRegionalConfigId;
+        }
+    }
+
     private void plogv(@NonNull String log) {
         Rlog.v(TAG, log);
         if (mPersistentLogger != null) {
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
index c8013d6..a47095d 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
@@ -22,6 +22,7 @@
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_PROVISIONED;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_SUPPORTED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_ACCESS_BARRED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_ERROR;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_DISABLED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_NOT_AVAILABLE;
@@ -44,6 +45,7 @@
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.GOOGLE_US_SAN_SAT_S2_FILE_NAME;
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -54,6 +56,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -98,10 +101,13 @@
 import android.telecom.TelecomManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.satellite.EarfcnRange;
 import android.telephony.satellite.ISatelliteCommunicationAllowedStateCallback;
 import android.telephony.satellite.SatelliteAccessConfiguration;
 import android.telephony.satellite.SatelliteInfo;
 import android.telephony.satellite.SatelliteManager;
+import android.telephony.satellite.SatellitePosition;
+import android.telephony.satellite.SystemSelectionSpecifier;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.Log;
@@ -136,11 +142,14 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 /** Unit test for {@link SatelliteAccessController} */
 @RunWith(AndroidTestingRunner.class)
@@ -288,6 +297,22 @@
         }
     };
 
+    private int mQueriedSystemSelectionChannelUpdatedResultCode = SATELLITE_RESULT_SUCCESS;
+    private Semaphore mSystemSelectionChannelUpdatedSemaphore = new Semaphore(0);
+    private ResultReceiver mSystemSelectionChannelUpdatedReceiver = new ResultReceiver(null) {
+        @Override
+        protected void onReceiveResult(int resultCode, Bundle resultData) {
+            mQueriedSystemSelectionChannelUpdatedResultCode = resultCode;
+            try {
+                mSystemSelectionChannelUpdatedSemaphore.release();
+            } catch (Exception ex) {
+                fail("mSystemSelectionChannelUpdatedReceiver: Got exception in releasing "
+                        + "semaphore, ex="
+                        + ex);
+            }
+        }
+    };
+
     @Before
     public void setUp() throws Exception {
         super.setUp();
@@ -1530,7 +1555,7 @@
         // Captor and Verify if the mockReceiver and mocContext is registered well
         verify(mMockContext, times(2))
                 .registerReceiver(mLocationBroadcastReceiverCaptor.capture(),
-                mIntentFilterCaptor.capture());
+                        mIntentFilterCaptor.capture());
 
         // When the intent action is not MODE_CHANGED_ACTION,
         // verify if the location manager never invoke isLocationEnabled()
@@ -1710,6 +1735,311 @@
                 any(Consumer.class));
     }
 
+    @Test
+    public void testUpdateSystemSelectionChannels() {
+        // Set non-emergency case
+        when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+        when(mMockFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
+
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(EMPTY_STRING_LIST);
+
+        // Invoke when regional config ID is not set.
+        mSatelliteAccessControllerUT.setRegionalConfigId(null);
+        mSatelliteAccessControllerUT.updateSystemSelectionChannels(
+                mSystemSelectionChannelUpdatedReceiver);
+        mTestableLooper.processAllMessages();
+        assertTrue(waitForRequestUpdateSystemSelectionChannelResult(
+                mSystemSelectionChannelUpdatedSemaphore, 1));
+        assertEquals(SATELLITE_RESULT_ACCESS_BARRED,
+                mQueriedSystemSelectionChannelUpdatedResultCode);
+
+        // Invoke when mSatelliteAccessConfigMap does not have data for given regional config ID
+        int satelliteRegionalConfigId = DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
+        mSatelliteAccessControllerUT.setRegionalConfigId(satelliteRegionalConfigId);
+        mSatelliteAccessControllerUT.resetSatelliteAccessConfigMap();
+        mSatelliteAccessControllerUT.updateSystemSelectionChannels(
+                mSystemSelectionChannelUpdatedReceiver);
+        mTestableLooper.processAllMessages();
+        assertTrue(waitForRequestUpdateSystemSelectionChannelResult(
+                mSystemSelectionChannelUpdatedSemaphore, 1));
+        assertEquals(SATELLITE_RESULT_ACCESS_BARRED,
+                mQueriedSystemSelectionChannelUpdatedResultCode);
+
+        // Invoke when mSatelliteAccessConfigMap does not have data and given data is old format.
+        satelliteRegionalConfigId = UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID;
+        mSatelliteAccessControllerUT.setRegionalConfigId(satelliteRegionalConfigId);
+        mSatelliteAccessControllerUT.resetSatelliteAccessConfigMap();
+        mSatelliteAccessControllerUT.updateSystemSelectionChannels(
+                mSystemSelectionChannelUpdatedReceiver);
+        mTestableLooper.processAllMessages();
+        assertTrue(waitForRequestUpdateSystemSelectionChannelResult(
+                mSystemSelectionChannelUpdatedSemaphore, 1));
+        assertEquals(SATELLITE_RESULT_ACCESS_BARRED,
+                mQueriedSystemSelectionChannelUpdatedResultCode);
+
+        satelliteRegionalConfigId = DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
+        // Return success when SatelliteController.updateSystemSelectionChannels was invoked
+        setupResponseForUpdateSystemSelectionChannels(SATELLITE_RESULT_SUCCESS);
+
+        // Invoke updateSystemSelectionChannels when there is corresponding satellite access config.
+        // Create satellite info 1
+        String seed1 = "test-seed-satellite1";
+        UUID uuid1 = UUID.nameUUIDFromBytes(seed1.getBytes());
+        SatellitePosition satellitePosition1 = new SatellitePosition(0, 35876);
+        int[] bands1 = {200, 201, 202};
+        EarfcnRange earfcnRange1 = new EarfcnRange(300, 301);
+        EarfcnRange earfcnRange2 = new EarfcnRange(310, 311);
+        List<EarfcnRange> earfcnRangeList1 = new ArrayList<>(
+                Arrays.asList(earfcnRange1, earfcnRange2));
+        SatelliteInfo satelliteInfo1 = new SatelliteInfo(uuid1, satellitePosition1, Arrays.stream(
+                bands1).boxed().collect(Collectors.toList()), earfcnRangeList1);
+        // Create satellite info 2
+        String seed2 = "test-seed-satellite2";
+        UUID uuid2 = UUID.nameUUIDFromBytes(seed2.getBytes());
+        SatellitePosition satellitePosition2 = new SatellitePosition(120, 35876);
+        int[] bands2 = {210, 211, 212};
+        EarfcnRange earfcnRange3 = new EarfcnRange(320, 321);
+        EarfcnRange earfcnRange4 = new EarfcnRange(330, 331);
+        List<EarfcnRange> earfcnRangeList2 = new ArrayList<>(
+                Arrays.asList(earfcnRange3, earfcnRange4));
+        SatelliteInfo satelliteInfo2 = new SatelliteInfo(uuid2, satellitePosition2, Arrays.stream(
+                bands2).boxed().collect(Collectors.toList()), earfcnRangeList2);
+        // Create satellite info 3
+        String seed3 = "test-seed-satellite3";
+        UUID uuid3 = UUID.nameUUIDFromBytes(seed3.getBytes());
+        SatellitePosition satellitePosition3 = new SatellitePosition(120, 35876);
+        int[] bands3 = {220, 221, 222};
+        EarfcnRange earfcnRange5 = new EarfcnRange(340, 341);
+        EarfcnRange earfcnRange6 = new EarfcnRange(350, 351);
+        List<EarfcnRange> earfcnRangeList3 = new ArrayList<>(
+                Arrays.asList(earfcnRange5, earfcnRange6));
+        SatelliteInfo satelliteInfo3 = new SatelliteInfo(uuid3, satellitePosition3, Arrays.stream(
+                bands3).boxed().collect(Collectors.toList()), earfcnRangeList3);
+
+        int[] tagIds = {1, 2, 3};
+        SatelliteAccessConfiguration satelliteAccessConfiguration =
+                new SatelliteAccessConfiguration(new ArrayList<>(
+                        Arrays.asList(satelliteInfo1, satelliteInfo2, satelliteInfo3)),
+                        Arrays.stream(tagIds).boxed().collect(Collectors.toList()));
+
+        // Add satellite access configuration to map
+        mSatelliteAccessControllerUT.setSatelliteAccessConfigMap(satelliteRegionalConfigId,
+                satelliteAccessConfiguration);
+
+        // Invoke updateSystemSelectionChannel
+        mSatelliteAccessControllerUT.updateSystemSelectionChannels(
+                mSystemSelectionChannelUpdatedReceiver);
+        mTestableLooper.processAllMessages();
+        assertTrue(waitForRequestUpdateSystemSelectionChannelResult(
+                mSystemSelectionChannelUpdatedSemaphore, 1));
+        assertEquals(SATELLITE_RESULT_SUCCESS,
+                mQueriedSystemSelectionChannelUpdatedResultCode);
+        ArgumentCaptor<List<SystemSelectionSpecifier>> systemSelectionSpecifierListCaptor =
+                ArgumentCaptor.forClass(List.class);
+        verify(mMockSatelliteController, times(1)).updateSystemSelectionChannels(
+                systemSelectionSpecifierListCaptor.capture(), any(ResultReceiver.class));
+        List<SystemSelectionSpecifier> capturedList = systemSelectionSpecifierListCaptor.getValue();
+        SystemSelectionSpecifier systemSelectionSpecifier = capturedList.getFirst();
+
+        // Verify the fields value of given systemSelectionSpecifier matched with expected.
+        int[] expectedBandsArray = IntStream.concat(
+                IntStream.concat(Arrays.stream(bands1), Arrays.stream(bands2)),
+                Arrays.stream(bands3)).toArray();
+        int[] actualBandsArray = IntStream.range(0, systemSelectionSpecifier.getBands().size()).map(
+                systemSelectionSpecifier.getBands()::get).toArray();
+        assertArrayEquals(expectedBandsArray, actualBandsArray);
+
+        int[] expectedEarfcnsArray = {300, 301, 310, 311, 320, 321, 330, 331, 340, 341, 350, 351};
+        int[] actualEarfcnsArray = IntStream.range(0,
+                systemSelectionSpecifier.getEarfcns().size()).map(
+                systemSelectionSpecifier.getEarfcns()::get).toArray();
+        assertArrayEquals(expectedEarfcnsArray, actualEarfcnsArray);
+
+        SatelliteInfo[] expectedSatelliteInfos = {satelliteInfo1, satelliteInfo2, satelliteInfo3};
+        assertArrayEquals(expectedSatelliteInfos, systemSelectionSpecifier.getSatelliteInfos());
+
+        int[] actualTagIdArray = IntStream.range(0,
+                systemSelectionSpecifier.getTagIds().size()).map(
+                systemSelectionSpecifier.getTagIds()::get).toArray();
+        assertArrayEquals(tagIds, actualTagIdArray);
+
+        // Verify backward compatibility when there is valid data for default regional config ID
+        satelliteRegionalConfigId = UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID;
+        mSatelliteAccessControllerUT.setRegionalConfigId(satelliteRegionalConfigId);
+        mSatelliteAccessControllerUT.updateSystemSelectionChannels(
+                mSystemSelectionChannelUpdatedReceiver);
+        mTestableLooper.processAllMessages();
+
+        // updateSelectionChannelResult will be invoked with the data for default regional config ID
+        assertTrue(waitForRequestUpdateSystemSelectionChannelResult(
+                mSystemSelectionChannelUpdatedSemaphore, 1));
+        systemSelectionSpecifierListCaptor = ArgumentCaptor.forClass(List.class);
+        verify(mMockSatelliteController, times(2)).updateSystemSelectionChannels(
+                systemSelectionSpecifierListCaptor.capture(), any(ResultReceiver.class));
+        capturedList = systemSelectionSpecifierListCaptor.getValue();
+        systemSelectionSpecifier = capturedList.getFirst();
+
+        // Data will be same with default regional config ID
+
+        // Verify the fields value of given systemSelectionSpecifier matched with expected.
+        actualBandsArray = IntStream.range(0, systemSelectionSpecifier.getBands().size()).map(
+                systemSelectionSpecifier.getBands()::get).toArray();
+        assertArrayEquals(expectedBandsArray, actualBandsArray);
+
+        actualEarfcnsArray = IntStream.range(0,
+                systemSelectionSpecifier.getEarfcns().size()).map(
+                systemSelectionSpecifier.getEarfcns()::get).toArray();
+        assertArrayEquals(expectedEarfcnsArray, actualEarfcnsArray);
+
+        assertArrayEquals(expectedSatelliteInfos, systemSelectionSpecifier.getSatelliteInfos());
+
+        actualTagIdArray = IntStream.range(0,
+                systemSelectionSpecifier.getTagIds().size()).map(
+                systemSelectionSpecifier.getTagIds()::get).toArray();
+        assertArrayEquals(tagIds, actualTagIdArray);
+
+        mSatelliteAccessControllerUT.resetSatelliteAccessConfigMap();
+    }
+
+    @Test
+    public void testUpdateSystemSelectionChannels_HandleInvalidInput() {
+        // Set non-emergency case
+        when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+        when(mMockFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
+
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(EMPTY_STRING_LIST);
+        int satelliteRegionalConfigId = DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
+        mSatelliteAccessControllerUT.setRegionalConfigId(satelliteRegionalConfigId);
+        // Set return success when SatelliteController.updateSystemSelectionChannels was invoked
+        setupResponseForUpdateSystemSelectionChannels(SATELLITE_RESULT_SUCCESS);
+
+        // Create satellite info in which satellite position is null.
+        String seed1 = "test-seed-satellite1";
+        UUID uuid1 = UUID.nameUUIDFromBytes(seed1.getBytes());
+        SatellitePosition satellitePosition1 = null;
+        List<Integer> bandList1 = new ArrayList<>(List.of(200, 201, 202));
+        EarfcnRange earfcnRange1 = new EarfcnRange(300, 301);
+        EarfcnRange earfcnRange2 = new EarfcnRange(310, 311);
+        List<EarfcnRange> earfcnRangeList1 = new ArrayList<>(
+                Arrays.asList(earfcnRange1, earfcnRange2));
+        SatelliteInfo satelliteInfo1 = new SatelliteInfo(uuid1, satellitePosition1, bandList1,
+                earfcnRangeList1);
+
+        // Create satellite info in which band list is empty
+        String seed2 = "test-seed-satellite2";
+        UUID uuid2 = UUID.nameUUIDFromBytes(seed2.getBytes());
+        SatellitePosition satellitePosition2 = new SatellitePosition(120, 35876);
+        List<Integer> bandList2 = new ArrayList<>();
+        EarfcnRange earfcnRange3 = new EarfcnRange(320, 321);
+        EarfcnRange earfcnRange4 = new EarfcnRange(330, 331);
+        List<EarfcnRange> earfcnRangeList2 = new ArrayList<>(
+                Arrays.asList(earfcnRange3, earfcnRange4));
+        SatelliteInfo satelliteInfo2 = new SatelliteInfo(uuid2, satellitePosition2, bandList2,
+                earfcnRangeList2);
+
+        // Create satellite info 3, every field is valid
+        String seed3 = "test-seed-satellite3";
+        UUID uuid3 = UUID.nameUUIDFromBytes(seed3.getBytes());
+        SatellitePosition satellitePosition3 = new SatellitePosition(120, 35876);
+        List<Integer> bandList3 = new ArrayList<>(List.of(220, 221, 222));
+        EarfcnRange earfcnRange5 = new EarfcnRange(340, 341);
+        EarfcnRange earfcnRange6 = new EarfcnRange(350, 351);
+        List<EarfcnRange> earfcnRangeList3 = new ArrayList<>(
+                Arrays.asList(earfcnRange5, earfcnRange6));
+        SatelliteInfo satelliteInfo3 = new SatelliteInfo(uuid3, satellitePosition3, bandList3,
+                earfcnRangeList3);
+        // Add empty tagId list
+        List<Integer> tagIdList = new ArrayList<>();
+
+        // Create satelliteAccessConfiguration with some of files of added Satellite info are empty.
+        SatelliteAccessConfiguration satelliteAccessConfiguration1 =
+                new SatelliteAccessConfiguration(new ArrayList<>(
+                        Arrays.asList(satelliteInfo1, satelliteInfo2, satelliteInfo3)), tagIdList);
+
+        // Add satellite access configuration to map
+        mSatelliteAccessControllerUT.setSatelliteAccessConfigMap(satelliteRegionalConfigId,
+                satelliteAccessConfiguration1);
+
+        // Invoke updateSystemSelectionChannel
+        mSatelliteAccessControllerUT.updateSystemSelectionChannels(
+                mSystemSelectionChannelUpdatedReceiver);
+        mTestableLooper.processAllMessages();
+        assertTrue(waitForRequestUpdateSystemSelectionChannelResult(
+                mSystemSelectionChannelUpdatedSemaphore, 1));
+        assertEquals(SATELLITE_RESULT_SUCCESS,
+                mQueriedSystemSelectionChannelUpdatedResultCode);
+        ArgumentCaptor<List<SystemSelectionSpecifier>> systemSelectionSpecifierListCaptor =
+                ArgumentCaptor.forClass(List.class);
+        verify(mMockSatelliteController, times(1)).updateSystemSelectionChannels(
+                systemSelectionSpecifierListCaptor.capture(), any(ResultReceiver.class));
+        List<SystemSelectionSpecifier> capturedList = systemSelectionSpecifierListCaptor.getValue();
+        SystemSelectionSpecifier systemSelectionSpecifier = capturedList.getFirst();
+
+        // Verify the fields value of given systemSelectionSpecifier matched with expected.
+        List<Integer> expectedBandList = new ArrayList<>(bandList1);
+        expectedBandList.addAll(bandList2);
+        expectedBandList.addAll(bandList3);
+
+        List<Integer> actualBandList = IntStream.range(0,
+                systemSelectionSpecifier.getBands().size()).map(
+                systemSelectionSpecifier.getBands()::get).boxed().toList();
+        assertEquals(expectedBandList, actualBandList);
+
+        List<Integer> expectedEarfcnList = new ArrayList<>(
+                List.of(300, 301, 310, 311, 320, 321, 330, 331, 340, 341, 350, 351));
+        List<Integer> actualEarfcnList = IntStream.range(0,
+                systemSelectionSpecifier.getEarfcns().size()).map(
+                systemSelectionSpecifier.getEarfcns()::get).boxed().toList();
+        assertEquals(expectedEarfcnList, actualEarfcnList);
+
+        assertEquals(satelliteInfo1, systemSelectionSpecifier.getSatelliteInfos()[0]);
+        assertEquals(satelliteInfo2, systemSelectionSpecifier.getSatelliteInfos()[1]);
+        assertEquals(satelliteInfo3, systemSelectionSpecifier.getSatelliteInfos()[2]);
+
+        List<Integer> actualTagIdList = IntStream.range(0,
+                systemSelectionSpecifier.getTagIds().size()).map(
+                systemSelectionSpecifier.getTagIds()::get).boxed().toList();
+        assertEquals(tagIdList, actualTagIdList);
+
+        // Create satelliteAccessConfiguration with empty list of SatelliteInfo.
+        SatelliteAccessConfiguration satelliteAccessConfiguration2 =
+                new SatelliteAccessConfiguration(new ArrayList<>(), tagIdList);
+        mSatelliteAccessControllerUT.setSatelliteAccessConfigMap(
+                DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, satelliteAccessConfiguration2);
+
+        // Invoke updateSystemSelectionChannel
+        mSatelliteAccessControllerUT.updateSystemSelectionChannels(
+                mSystemSelectionChannelUpdatedReceiver);
+        mTestableLooper.processAllMessages();
+        assertTrue(waitForRequestUpdateSystemSelectionChannelResult(
+                mSystemSelectionChannelUpdatedSemaphore, 1));
+        assertEquals(SATELLITE_RESULT_SUCCESS,
+                mQueriedSystemSelectionChannelUpdatedResultCode);
+        systemSelectionSpecifierListCaptor = ArgumentCaptor.forClass(List.class);
+        verify(mMockSatelliteController, times(2)).updateSystemSelectionChannels(
+                systemSelectionSpecifierListCaptor.capture(), any(ResultReceiver.class));
+        capturedList = systemSelectionSpecifierListCaptor.getValue();
+        systemSelectionSpecifier = capturedList.getFirst();
+
+        // Verify the fields value of given systemSelectionSpecifier matched with expected.
+        assertEquals(0, systemSelectionSpecifier.getBands().size());
+        assertEquals(0, systemSelectionSpecifier.getEarfcns().size());
+
+        SatelliteInfo[] expectedSatelliteInfoArray = new SatelliteInfo[0];
+        assertArrayEquals(expectedSatelliteInfoArray, systemSelectionSpecifier.getSatelliteInfos());
+
+        actualTagIdList = IntStream.range(0,
+                systemSelectionSpecifier.getTagIds().size()).map(
+                systemSelectionSpecifier.getTagIds()::get).boxed().toList();
+        assertEquals(tagIdList, actualTagIdList);
+
+        mSatelliteAccessControllerUT.resetSatelliteAccessConfigMap();
+    }
+
     private void sendSatelliteCommunicationAllowedEvent() {
         Pair<Integer, ResultReceiver> requestPair =
                 new Pair<>(DEFAULT_SUBSCRIPTION_ID,
@@ -1721,7 +2051,6 @@
         mTestableLooper.processAllMessages();
     }
 
-
     private void sendConfigUpdateChangedEvent(Context context) {
         Message msg = mSatelliteAccessControllerUT.obtainMessage(EVENT_CONFIG_DATA_UPDATED);
         msg.obj = new AsyncResult(context, SATELLITE_RESULT_SUCCESS, null);
@@ -1774,6 +2103,24 @@
         return true;
     }
 
+    private boolean waitForRequestUpdateSystemSelectionChannelResult(Semaphore semaphore,
+            int expectedNumberOfEvents) {
+        for (int i = 0; i < expectedNumberOfEvents; i++) {
+            try {
+                if (!semaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) {
+                    logd("Timeout to receive "
+                            + "updateSystemSelectionChannel()"
+                            + " callback");
+                    return false;
+                }
+            } catch (Exception ex) {
+                logd("updateSystemSelectionChannel: Got exception=" + ex);
+                return false;
+            }
+        }
+        return true;
+    }
+
     private void sendLocationRequestResult(Location location) {
         mLocationRequestConsumerCaptor.getValue().accept(location);
         mTestableLooper.processAllMessages();
@@ -1810,6 +2157,16 @@
         }).when(mMockSatelliteController).requestIsSatelliteProvisioned(any(ResultReceiver.class));
     }
 
+    private void setupResponseForUpdateSystemSelectionChannels(
+            @SatelliteManager.SatelliteResult int error) {
+        doAnswer(invocation -> {
+            ResultReceiver resultReceiver = invocation.getArgument(1);
+            resultReceiver.send(error, null);
+            return null;
+        }).when(mMockSatelliteController).updateSystemSelectionChannels(anyList(),
+                any(ResultReceiver.class));
+    }
+
     @SafeVarargs
     private static <E> List<E> listOf(E... values) {
         return Arrays.asList(values);
@@ -1925,5 +2282,25 @@
                 mRegionalConfigId = regionalConfigId;
             }
         }
+
+        public void setSatelliteAccessConfigMap(int regionalConfigId,
+                SatelliteAccessConfiguration satelliteAccessConfiguration) {
+            synchronized (mLock) {
+                if (mSatelliteAccessConfigMap == null) {
+                    mSatelliteAccessConfigMap = new HashMap<>();
+                }
+                mSatelliteAccessConfigMap.put(regionalConfigId, satelliteAccessConfiguration);
+            }
+        }
+
+        public void resetSatelliteAccessConfigMap() {
+            synchronized (mLock) {
+                if (mSatelliteAccessConfigMap == null) {
+                    mSatelliteAccessConfigMap = new HashMap<>();
+                } else {
+                    mSatelliteAccessConfigMap.clear();
+                }
+            }
+        }
     }
 }