• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.android.iwlan.epdg;
18 
19 import android.content.Context;
20 import android.net.Network;
21 import android.support.annotation.IntDef;
22 import android.support.annotation.NonNull;
23 import android.telephony.CarrierConfigManager;
24 import android.telephony.CellIdentityGsm;
25 import android.telephony.CellIdentityLte;
26 import android.telephony.CellIdentityNr;
27 import android.telephony.CellIdentityWcdma;
28 import android.telephony.CellInfo;
29 import android.telephony.CellInfoGsm;
30 import android.telephony.CellInfoLte;
31 import android.telephony.CellInfoNr;
32 import android.telephony.CellInfoWcdma;
33 import android.telephony.SubscriptionInfo;
34 import android.telephony.SubscriptionManager;
35 import android.telephony.TelephonyManager;
36 import android.util.Log;
37 
38 import com.android.internal.annotations.VisibleForTesting;
39 
40 import com.google.android.iwlan.IwlanError;
41 import com.google.android.iwlan.IwlanHelper;
42 
43 import java.net.Inet4Address;
44 import java.net.Inet6Address;
45 import java.net.InetAddress;
46 import java.util.*;
47 import java.util.concurrent.ConcurrentHashMap;
48 
49 public class EpdgSelector {
50     private static final String TAG = "EpdgSelector";
51     private Context mContext;
52     private int mSlotId;
53     private static ConcurrentHashMap<Integer, EpdgSelector> mSelectorInstances =
54             new ConcurrentHashMap<>();
55     private int mV4PcoId = -1;
56     private int mV6PcoId = -1;
57     private byte[] mV4PcoData = null;
58     private byte[] mV6PcoData = null;
59 
60     final Comparator<InetAddress> inetAddressComparator =
61             new Comparator<InetAddress>() {
62                 @Override
63                 public int compare(InetAddress ip1, InetAddress ip2) {
64                     if ((ip1 instanceof Inet4Address) && (ip2 instanceof Inet6Address)) {
65                         return -1;
66                     } else if ((ip1 instanceof Inet6Address) && (ip2 instanceof Inet4Address)) {
67                         return 1;
68                     } else {
69                         return 0;
70                     }
71                 }
72             };
73 
74     public static final int PROTO_FILTER_IPV4 = 0;
75     public static final int PROTO_FILTER_IPV6 = 1;
76     public static final int PROTO_FILTER_IPV4V6 = 2;
77 
78     @IntDef({PROTO_FILTER_IPV4, PROTO_FILTER_IPV6, PROTO_FILTER_IPV4V6})
79     @interface ProtoFilter {}
80 
81     public interface EpdgSelectorCallback {
82         /*gives priority ordered list of addresses*/
onServerListChanged(int transactionId, ArrayList<InetAddress> validIPList)83         void onServerListChanged(int transactionId, ArrayList<InetAddress> validIPList);
84 
onError(int transactionId, IwlanError error)85         void onError(int transactionId, IwlanError error);
86     }
87 
88     @VisibleForTesting
EpdgSelector(Context context, int slotId)89     EpdgSelector(Context context, int slotId) {
90         mContext = context;
91         mSlotId = slotId;
92     }
93 
getSelectorInstance(Context context, int slotId)94     public static EpdgSelector getSelectorInstance(Context context, int slotId) {
95         mSelectorInstances.computeIfAbsent(slotId, k -> new EpdgSelector(context, slotId));
96         return mSelectorInstances.get(slotId);
97     }
98 
setPcoData(int pcoId, byte[] pcoData)99     public boolean setPcoData(int pcoId, byte[] pcoData) {
100         Log.d(TAG, "onReceive PcoId:" + String.format("0x%04x", pcoId) + " PcoData:" + pcoData);
101 
102         int PCO_ID_IPV6 =
103                 IwlanHelper.getConfig(
104                         CarrierConfigManager.Iwlan.KEY_EPDG_PCO_ID_IPV6_INT, mContext, mSlotId);
105         int PCO_ID_IPV4 =
106                 IwlanHelper.getConfig(
107                         CarrierConfigManager.Iwlan.KEY_EPDG_PCO_ID_IPV4_INT, mContext, mSlotId);
108 
109         Log.d(
110                 TAG,
111                 "PCO_ID_IPV6:"
112                         + String.format("0x%04x", PCO_ID_IPV6)
113                         + " PCO_ID_IPV4:"
114                         + String.format("0x%04x", PCO_ID_IPV4));
115 
116         if (pcoId == PCO_ID_IPV4) {
117             mV4PcoId = pcoId;
118             mV4PcoData = pcoData;
119             return true;
120         } else if (pcoId == PCO_ID_IPV6) {
121             mV6PcoId = pcoId;
122             mV6PcoData = pcoData;
123             return true;
124         }
125 
126         return false;
127     }
128 
clearPcoData()129     public void clearPcoData() {
130         Log.d(TAG, "Clear PCO data");
131         mV4PcoId = -1;
132         mV6PcoId = -1;
133         mV4PcoData = null;
134         mV6PcoData = null;
135     }
136 
getIP( String domainName, int filter, ArrayList<InetAddress> validIpList, Network network)137     private void getIP(
138             String domainName, int filter, ArrayList<InetAddress> validIpList, Network network) {
139         InetAddress[] ipList;
140 
141         // Get All IP for each domain name
142         Log.d(TAG, "Input domainName : " + domainName);
143         try {
144             ipList = network.getAllByName(domainName);
145         } catch (Exception e) {
146             Log.e(TAG, "Exception when querying IP address : " + e);
147             return;
148         }
149 
150         if (ipList == null) {
151             Log.e(TAG, "Get empty IP address list");
152             return;
153         }
154 
155         // Filter the IP list by input ProtoFilter
156         for (InetAddress ipAddress : ipList) {
157             switch (filter) {
158                 case PROTO_FILTER_IPV4:
159                     if (ipAddress instanceof Inet4Address) {
160                         validIpList.add(ipAddress);
161                     }
162                     break;
163                 case PROTO_FILTER_IPV6:
164                     if (ipAddress instanceof Inet6Address) {
165                         validIpList.add(ipAddress);
166                     }
167                     break;
168                 case PROTO_FILTER_IPV4V6:
169                     validIpList.add(ipAddress);
170                     break;
171                 default:
172                     Log.d(TAG, "Invalid ProtoFilter : " + filter);
173             }
174         }
175     }
176 
getPlmnList()177     private String[] getPlmnList() {
178         List<String> plmnsFromSubInfo = new ArrayList<>();
179 
180         List<String> plmnsFromCarrierConfig =
181                 new ArrayList<>(
182                         Arrays.asList(
183                                 IwlanHelper.getConfig(
184                                         CarrierConfigManager.Iwlan.KEY_MCC_MNCS_STRING_ARRAY,
185                                         mContext,
186                                         mSlotId)));
187         Log.d(TAG, "plmnsFromCarrierConfig:" + plmnsFromCarrierConfig);
188 
189         // Get Ehplmns & mccmnc from SubscriptionManager
190         SubscriptionManager subscriptionManager =
191                 mContext.getSystemService(SubscriptionManager.class);
192         if (subscriptionManager == null) {
193             Log.e(TAG, "SubscriptionManager is NULL");
194             return plmnsFromCarrierConfig.toArray(new String[plmnsFromCarrierConfig.size()]);
195         }
196 
197         SubscriptionInfo subInfo =
198                 subscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(mSlotId);
199         if (subInfo == null) {
200             Log.e(TAG, "SubscriptionInfo is NULL");
201             return plmnsFromCarrierConfig.toArray(new String[plmnsFromCarrierConfig.size()]);
202         }
203 
204         // There are three sources of plmns - sim plmn, plmn list from carrier config and
205         // Ehplmn list from subscription info.
206         // The plmns are prioritized as follows:
207         // 1. Sim plmn
208         // 2. Plmns common to both lists.
209         // 3. Remaining plmns in the lists.
210         List<String> combinedList = new ArrayList<>();
211         // Get MCCMNC from IMSI
212         String plmnFromImsi =
213                 new StringBuilder()
214                         .append(subInfo.getMccString())
215                         .append("-")
216                         .append(subInfo.getMncString())
217                         .toString();
218         combinedList.add(plmnFromImsi);
219 
220         // Get Ehplmns from TelephonyManager
221         for (String ehplmn : getEhplmns()) {
222             if (ehplmn.length() == 5 || ehplmn.length() == 6) {
223                 StringBuilder str = new StringBuilder(ehplmn);
224                 str.insert(3, "-");
225                 plmnsFromSubInfo.add(str.toString());
226             }
227         }
228 
229         Log.d(TAG, "plmnsFromSubInfo:" + plmnsFromSubInfo);
230 
231         // To avoid double adding plmn from imsi
232         plmnsFromCarrierConfig.removeIf(i -> i.equals(plmnFromImsi));
233         plmnsFromSubInfo.removeIf(i -> i.equals(plmnFromImsi));
234 
235         for (Iterator<String> iterator = plmnsFromCarrierConfig.iterator(); iterator.hasNext(); ) {
236             String plmn = iterator.next();
237             if (plmnsFromSubInfo.contains(plmn)) {
238                 combinedList.add(plmn);
239                 plmnsFromSubInfo.remove(plmn);
240                 iterator.remove();
241             }
242         }
243 
244         combinedList.addAll(plmnsFromSubInfo);
245         combinedList.addAll(plmnsFromCarrierConfig);
246 
247         Log.d(TAG, "Final plmn list:" + combinedList);
248         return combinedList.toArray(new String[combinedList.size()]);
249     }
250 
removeDuplicateIp(ArrayList<InetAddress> validIpList)251     private ArrayList<InetAddress> removeDuplicateIp(ArrayList<InetAddress> validIpList) {
252         ArrayList<InetAddress> resultIpList = new ArrayList<InetAddress>();
253 
254         for (Iterator<InetAddress> iterator = validIpList.iterator(); iterator.hasNext(); ) {
255             InetAddress validIp = iterator.next();
256 
257             if (!resultIpList.contains(validIp)) {
258                 resultIpList.add(validIp);
259             }
260         }
261 
262         return resultIpList;
263     }
264 
splitMccMnc(String plmn)265     private String[] splitMccMnc(String plmn) {
266         String[] mccmnc = plmn.split("-");
267         mccmnc[1] = String.format("%03d", Integer.parseInt(mccmnc[1]));
268         return mccmnc;
269     }
270 
getEhplmns()271     private List<String> getEhplmns() {
272         TelephonyManager mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
273         mTelephonyManager =
274                 mTelephonyManager.createForSubscriptionId(IwlanHelper.getSubId(mContext, mSlotId));
275 
276         if (mTelephonyManager == null) {
277             Log.e(TAG, "TelephonyManager is NULL");
278             return new ArrayList<String>();
279         } else {
280             return mTelephonyManager.getEquivalentHomePlmns();
281         }
282     }
283 
resolutionMethodStatic( int filter, ArrayList<InetAddress> validIpList, boolean isRoaming, Network network)284     private void resolutionMethodStatic(
285             int filter, ArrayList<InetAddress> validIpList, boolean isRoaming, Network network) {
286         String[] domainNames = null;
287 
288         Log.d(TAG, "STATIC Method");
289 
290         // Get the static domain names from carrier config
291         // Config obtained in form of a list of domain names separated by
292         // a delimeter is only used for testing purpose.
293         // TODO: need to consider APM on/no cellular condition.
294         if (isRoaming && !inSameCountry()) {
295             domainNames =
296                     getDomainNames(
297                             CarrierConfigManager.Iwlan.KEY_EPDG_STATIC_ADDRESS_ROAMING_STRING);
298         }
299         if (domainNames == null
300                 && (domainNames =
301                                 getDomainNames(
302                                         CarrierConfigManager.Iwlan.KEY_EPDG_STATIC_ADDRESS_STRING))
303                         == null) {
304             Log.d(TAG, "Static address string is null");
305             return;
306         }
307 
308         Log.d(TAG, "Static Domain Names: " + Arrays.toString(domainNames));
309         for (String domainName : domainNames) {
310             getIP(domainName, filter, validIpList, network);
311         }
312     }
313 
getDomainNames(String key)314     private String[] getDomainNames(String key) {
315         String configValue = (String) IwlanHelper.getConfig(key, mContext, mSlotId);
316         if (configValue == null || configValue.isEmpty()) {
317             Log.d(TAG, key + " string is null");
318             return null;
319         }
320         return configValue.split(",");
321     }
322 
inSameCountry()323     private boolean inSameCountry() {
324         boolean inSameCountry = true;
325 
326         TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
327         tm = tm.createForSubscriptionId(IwlanHelper.getSubId(mContext, mSlotId));
328 
329         if (tm != null) {
330             String simCountry = tm.getSimCountryIso();
331             String currentCountry = tm.getNetworkCountryIso();
332             if (simCountry != null
333                     && !simCountry.isEmpty()
334                     && currentCountry != null
335                     && !currentCountry.isEmpty()) {
336                 Log.d(TAG, "simCountry = " + simCountry + ", currentCountry = " + currentCountry);
337                 inSameCountry = simCountry.equalsIgnoreCase(currentCountry);
338             }
339         }
340 
341         return inSameCountry;
342     }
343 
resolutionMethodPlmn( int filter, ArrayList<InetAddress> validIpList, boolean isEmergency, Network network)344     private void resolutionMethodPlmn(
345             int filter, ArrayList<InetAddress> validIpList, boolean isEmergency, Network network) {
346         String[] plmnList;
347         StringBuilder domainName = new StringBuilder();
348 
349         Log.d(TAG, "PLMN Method");
350 
351         plmnList = getPlmnList();
352         for (String plmn : plmnList) {
353             String[] mccmnc = splitMccMnc(plmn);
354             /*
355              * Operator Identifier based ePDG FQDN format:
356              * epdg.epc.mnc<MNC>.mcc<MCC>.pub.3gppnetwork.org
357              *
358              * Operator Identifier based Emergency ePDG FQDN format:
359              * sos.epdg.epc.mnc<MNC>.mcc<MCC>.pub.3gppnetwork.org
360              */
361             if (isEmergency) {
362                 domainName.append("sos.");
363             }
364 
365             domainName
366                     .append("epdg.epc.mnc")
367                     .append(mccmnc[1])
368                     .append(".mcc")
369                     .append(mccmnc[0])
370                     .append(".pub.3gppnetwork.org");
371             getIP(domainName.toString(), filter, validIpList, network);
372             domainName.setLength(0);
373         }
374     }
375 
resolutionMethodCellularLoc( int filter, ArrayList<InetAddress> validIpList, boolean isEmergency, Network network)376     private void resolutionMethodCellularLoc(
377             int filter, ArrayList<InetAddress> validIpList, boolean isEmergency, Network network) {
378         String[] plmnList;
379         StringBuilder domainName = new StringBuilder();
380 
381         Log.d(TAG, "CELLULAR_LOC Method");
382 
383         TelephonyManager mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
384         mTelephonyManager =
385                 mTelephonyManager.createForSubscriptionId(IwlanHelper.getSubId(mContext, mSlotId));
386 
387         if (mTelephonyManager == null) {
388             Log.e(TAG, "TelephonyManager is NULL");
389             return;
390         }
391 
392         List<CellInfo> cellInfoList = mTelephonyManager.getAllCellInfo();
393         if (cellInfoList == null) {
394             Log.e(TAG, "cellInfoList is NULL");
395             return;
396         }
397 
398         for (CellInfo cellInfo : cellInfoList) {
399             if (!cellInfo.isRegistered()) {
400                 continue;
401             }
402 
403             if (cellInfo instanceof CellInfoGsm) {
404                 CellIdentityGsm gsmCellId = ((CellInfoGsm) cellInfo).getCellIdentity();
405                 String lacString = String.format("%04x", gsmCellId.getLac());
406 
407                 lacDomainNameResolution(filter, validIpList, lacString, isEmergency, network);
408             } else if (cellInfo instanceof CellInfoWcdma) {
409                 CellIdentityWcdma wcdmaCellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
410                 String lacString = String.format("%04x", wcdmaCellId.getLac());
411 
412                 lacDomainNameResolution(filter, validIpList, lacString, isEmergency, network);
413             } else if (cellInfo instanceof CellInfoLte) {
414                 CellIdentityLte lteCellId = ((CellInfoLte) cellInfo).getCellIdentity();
415                 String tacString = String.format("%04x", lteCellId.getTac());
416                 String[] tacSubString = new String[2];
417                 tacSubString[0] = tacString.substring(0, 2);
418                 tacSubString[1] = tacString.substring(2);
419 
420                 plmnList = getPlmnList();
421                 for (String plmn : plmnList) {
422                     String[] mccmnc = splitMccMnc(plmn);
423                     /**
424                      * Tracking Area Identity based ePDG FQDN format:
425                      * tac-lb<TAC-low-byte>.tac-hb<TAC-high-byte>.tac.
426                      * epdg.epc.mnc<MNC>.mcc<MCC>.pub.3gppnetwork.org
427                      *
428                      * <p>Tracking Area Identity based Emergency ePDG FQDN format:
429                      * tac-lb<TAC-low-byte>.tac-hb<TAC-highbyte>.tac.
430                      * sos.epdg.epc.mnc<MNC>.mcc<MCC>.pub.3gppnetwork.org"
431                      */
432                     domainName
433                             .append("tac-lb")
434                             .append(tacSubString[1])
435                             .append(".tac-hb")
436                             .append(tacSubString[0]);
437                     if (isEmergency) {
438                         domainName.append(".tac.sos.epdg.epc.mnc");
439                     } else {
440                         domainName.append(".tac.epdg.epc.mnc");
441                     }
442                     domainName
443                             .append(mccmnc[1])
444                             .append(".mcc")
445                             .append(mccmnc[0])
446                             .append(".pub.3gppnetwork.org");
447                     getIP(domainName.toString(), filter, validIpList, network);
448                     domainName.setLength(0);
449                 }
450             } else if (cellInfo instanceof CellInfoNr) {
451                 CellIdentityNr nrCellId =
452                         (CellIdentityNr) ((CellInfoNr) cellInfo).getCellIdentity();
453                 String tacString = String.format("%06x", nrCellId.getTac());
454                 String[] tacSubString = new String[3];
455                 tacSubString[0] = tacString.substring(0, 2);
456                 tacSubString[1] = tacString.substring(2, 4);
457                 tacSubString[2] = tacString.substring(4);
458 
459                 plmnList = getPlmnList();
460                 for (String plmn : plmnList) {
461                     String[] mccmnc = splitMccMnc(plmn);
462                     /**
463                      * 5GS Tracking Area Identity based ePDG FQDN format:
464                      * tac-lb<TAC-low-byte>.tac-mb<TAC-middle-byte>.tac-hb<TAC-high-byte>.
465                      * 5gstac.epdg.epc.mnc<MNC>.mcc<MCC>.pub.3gppnetwork.org
466                      *
467                      * <p>5GS Tracking Area Identity based Emergency ePDG FQDN format:
468                      * tac-lb<TAC-low-byte>.tac-mb<TAC-middle-byte>.tac-hb<TAC-high-byte>.
469                      * 5gstac.sos.epdg.epc.mnc<MNC>.mcc<MCC>.pub.3gppnetwork.org
470                      */
471                     domainName
472                             .append("tac-lb")
473                             .append(tacSubString[2])
474                             .append(".tac-mb")
475                             .append(tacSubString[1])
476                             .append(".tac-hb")
477                             .append(tacSubString[0]);
478                     if (isEmergency) {
479                         domainName.append(".5gstac.sos.epdg.epc.mnc");
480                     } else {
481                         domainName.append(".5gstac.epdg.epc.mnc");
482                     }
483                     domainName
484                             .append(mccmnc[1])
485                             .append(".mcc")
486                             .append(mccmnc[0])
487                             .append(".pub.3gppnetwork.org");
488                     getIP(domainName.toString(), filter, validIpList, network);
489                     domainName.setLength(0);
490                 }
491             } else {
492                 Log.d(TAG, "This cell doesn't contain LAC/TAC info");
493             }
494         }
495     }
496 
lacDomainNameResolution( int filter, ArrayList<InetAddress> validIpList, String lacString, boolean isEmergency, Network network)497     private void lacDomainNameResolution(
498             int filter,
499             ArrayList<InetAddress> validIpList,
500             String lacString,
501             boolean isEmergency,
502             Network network) {
503         String[] plmnList;
504         StringBuilder domainName = new StringBuilder();
505 
506         plmnList = getPlmnList();
507         for (String plmn : plmnList) {
508             String[] mccmnc = splitMccMnc(plmn);
509             /**
510              * Location Area Identity based ePDG FQDN format:
511              * lac<LAC>.epdg.epc.mnc<MNC>.mcc<MCC>.pub.3gppnetwork.org
512              *
513              * <p>Location Area Identity based Emergency ePDG FQDN format:
514              * lac<LAC>.sos.epdg.epc.mnc<MNC>.mcc<MCC>.pub.3gppnetwork.org
515              */
516             domainName.append("lac").append(lacString);
517             if (isEmergency) {
518                 domainName.append(".sos.epdg.epc.mnc");
519             } else {
520                 domainName.append(".epdg.epc.mnc");
521             }
522             domainName
523                     .append(mccmnc[1])
524                     .append(".mcc")
525                     .append(mccmnc[0])
526                     .append(".pub.3gppnetwork.org");
527 
528             getIP(domainName.toString(), filter, validIpList, network);
529             domainName.setLength(0);
530         }
531     }
532 
resolutionMethodPco(int filter, ArrayList<InetAddress> validIpList)533     private void resolutionMethodPco(int filter, ArrayList<InetAddress> validIpList) {
534         Log.d(TAG, "PCO Method");
535 
536         int PCO_ID_IPV6 =
537                 IwlanHelper.getConfig(
538                         CarrierConfigManager.Iwlan.KEY_EPDG_PCO_ID_IPV6_INT, mContext, mSlotId);
539         int PCO_ID_IPV4 =
540                 IwlanHelper.getConfig(
541                         CarrierConfigManager.Iwlan.KEY_EPDG_PCO_ID_IPV4_INT, mContext, mSlotId);
542 
543         switch (filter) {
544             case PROTO_FILTER_IPV4:
545                 if (mV4PcoId != PCO_ID_IPV4) {
546                     clearPcoData();
547                 } else {
548                     getInetAddressWithPcoData(mV4PcoData, validIpList);
549                 }
550                 break;
551             case PROTO_FILTER_IPV6:
552                 if (mV6PcoId != PCO_ID_IPV6) {
553                     clearPcoData();
554                 } else {
555                     getInetAddressWithPcoData(mV6PcoData, validIpList);
556                 }
557                 break;
558             case PROTO_FILTER_IPV4V6:
559                 if ((mV4PcoId != PCO_ID_IPV4) || (mV6PcoId != PCO_ID_IPV6)) {
560                     clearPcoData();
561                 } else {
562                     getInetAddressWithPcoData(mV4PcoData, validIpList);
563                     getInetAddressWithPcoData(mV6PcoData, validIpList);
564                 }
565                 break;
566             default:
567                 Log.d(TAG, "Invalid ProtoFilter : " + filter);
568         }
569     }
570 
getInetAddressWithPcoData(byte[] pcoData, ArrayList<InetAddress> validIpList)571     private void getInetAddressWithPcoData(byte[] pcoData, ArrayList<InetAddress> validIpList) {
572         InetAddress ipAddress;
573         if (pcoData != null && pcoData.length > 0) {
574             try {
575                 ipAddress = InetAddress.getByAddress(pcoData);
576                 validIpList.add(ipAddress);
577             } catch (Exception e) {
578                 Log.e(TAG, "Exception when querying IP address : " + e);
579             }
580         } else {
581             Log.d(TAG, "Empty PCO data");
582         }
583     }
584 
getValidatedServerList( int transactionId, @ProtoFilter int filter, boolean isRoaming, boolean isEmergency, @NonNull Network network, EpdgSelectorCallback selectorCallback)585     public IwlanError getValidatedServerList(
586             int transactionId,
587             @ProtoFilter int filter,
588             boolean isRoaming,
589             boolean isEmergency,
590             @NonNull Network network,
591             EpdgSelectorCallback selectorCallback) {
592         ArrayList<InetAddress> validIpList = new ArrayList<InetAddress>();
593         StringBuilder domainName = new StringBuilder();
594 
595         Runnable doValidation =
596                 () -> {
597                     Log.d(TAG, "Processing request with transactionId: " + transactionId);
598                     String[] plmnList;
599 
600                     int[] addrResolutionMethods =
601                             IwlanHelper.getConfig(
602                                     CarrierConfigManager.Iwlan.KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
603                                     mContext,
604                                     mSlotId);
605 
606                     for (int addrResolutionMethod : addrResolutionMethods) {
607                         switch (addrResolutionMethod) {
608                             case CarrierConfigManager.Iwlan.EPDG_ADDRESS_STATIC:
609                                 resolutionMethodStatic(filter, validIpList, isRoaming, network);
610                                 break;
611 
612                             case CarrierConfigManager.Iwlan.EPDG_ADDRESS_PLMN:
613                                 resolutionMethodPlmn(filter, validIpList, isEmergency, network);
614                                 break;
615 
616                             case CarrierConfigManager.Iwlan.EPDG_ADDRESS_PCO:
617                                 resolutionMethodPco(filter, validIpList);
618                                 break;
619 
620                             case CarrierConfigManager.Iwlan.EPDG_ADDRESS_CELLULAR_LOC:
621                                 resolutionMethodCellularLoc(
622                                         filter, validIpList, isEmergency, network);
623                                 break;
624 
625                             default:
626                                 Log.d(
627                                         TAG,
628                                         "Incorrect address resolution method "
629                                                 + addrResolutionMethod);
630                         }
631                     }
632 
633                     if (selectorCallback != null) {
634                         if (!validIpList.isEmpty()) {
635                             Collections.sort(validIpList, inetAddressComparator);
636                             selectorCallback.onServerListChanged(
637                                     transactionId, removeDuplicateIp(validIpList));
638                         } else {
639                             selectorCallback.onError(
640                                     transactionId,
641                                     new IwlanError(
642                                             IwlanError.EPDG_SELECTOR_SERVER_SELECTION_FAILED));
643                         }
644                     }
645                 };
646         Thread subThread = new Thread(doValidation);
647         subThread.start();
648         return new IwlanError(IwlanError.NO_ERROR);
649     }
650 }
651