diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 05:08:01 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 05:08:01 +0000 |
commit | 8893d8abfe3a68f75fcae960062e6154e8d07322 (patch) | |
tree | 53a5565a52e2ee903caf5840cdb6569b722e2223 | |
parent | fedd5d54c25dfebb0963f2455b8621af5cbb81ee (diff) | |
parent | ac35454ec959667d4992f90acbdf86cc54e0c0be (diff) | |
download | carrier_settings-android14-mainline-extservices-release.tar.gz |
Snap for 10453563 from ac35454ec959667d4992f90acbdf86cc54e0c0be to mainline-extservices-releaseaml_ext_341620040aml_ext_341518010aml_ext_341414010aml_ext_341317010aml_ext_341131030aml_ext_341027030android14-mainline-extservices-release
Change-Id: I02513db890b54f1f95637e5b28900cd4d4292106
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | OWNERS | 5 | ||||
-rw-r--r-- | java/CarrierConfigConverterV2.java | 205 | ||||
-rw-r--r-- | proto/carrier_settings.proto | 2 | ||||
-rw-r--r-- | python/update_apn.py | 117 |
5 files changed, 303 insertions, 27 deletions
@@ -22,6 +22,7 @@ python_binary_host { srcs: [ "python/update_apn.py", "proto/*.proto", + ":telephonyprovider-proto-sources", ], proto: { canonical_path_from_root: false @@ -1,4 +1,3 @@ mewan@google.com -mberionne@google.com -amruthr@google.com -satk@google.com +cey@google.com +akaustubh@google.com diff --git a/java/CarrierConfigConverterV2.java b/java/CarrierConfigConverterV2.java index 2f8d254..feceabf 100644 --- a/java/CarrierConfigConverterV2.java +++ b/java/CarrierConfigConverterV2.java @@ -102,6 +102,9 @@ public final class CarrierConfigConverterV2 { @Parameter(names = "--version", description = "The version number for all output textpb.") private long version = 1L; + @Parameter(names = "--consider_parent_canonical_id", arity = 1, description = "To consider parent_canonical_id") + private static boolean considerParentCanonicalId = false; + private static final String MCCMNC_FOR_DEFAULT_SETTINGS = "000000"; // Resource file path to the AOSP carrier list file @@ -125,13 +128,14 @@ public final class CarrierConfigConverterV2 { /** Entry point when invoked from other Java code, eg. the server side conversion tool. */ public static void convert( - String vendorXmlFile, String assetsDirName, String outputDir, long version) + String vendorXmlFile, String assetsDirName, String outputDir, long version, boolean considerParentCanonicalId) throws IOException { CarrierConfigConverterV2 converter = new CarrierConfigConverterV2(); converter.vendorXmlFiles = ImmutableList.of(vendorXmlFile); converter.assetsDirName = assetsDirName; converter.outputDir = outputDir; converter.version = version; + converter.considerParentCanonicalId = considerParentCanonicalId; converter.convert(); } @@ -147,6 +151,7 @@ public final class CarrierConfigConverterV2 { DocumentBuilder xmlDocBuilder = getDocumentBuilder(); Multimap<Integer, CarrierId> aospCarrierList = loadAospCarrierList(); Multimap<CarrierId, Integer> reverseAospCarrierList = reverseAospCarrierList(aospCarrierList); + Multimap<CarrierId, Integer> reverseAospCarrierListPerParentCanonicalId = reverseAospCarrierListPerParentCanonicalId(); /* * High-level flow: @@ -264,10 +269,11 @@ public final class CarrierConfigConverterV2 { } // 3. For each CarrierId, build its carrier configs, following AOSP DefaultCarrierConfigService. + loadUniqueRulesFromVendorXml(vendorXmls); for (CarrierId carrier : carriers) { Map<String, CarrierConfig.Config> config = ImmutableMap.of(); - CarrierIdentifier id = getCid(carrier, reverseAospCarrierList); + CarrierIdentifier id = getCid(carrier, reverseAospCarrierList, reverseAospCarrierListPerParentCanonicalId); if (id.getCarrierId() != -1) { HashMap<String, CarrierConfig.Config> configBySpecificCarrierId = parseCarrierConfigFromXml( @@ -407,6 +413,31 @@ public final class CarrierConfigConverterV2 { MultimapBuilder.linkedHashKeys().arrayListValues()::build)); } + private static Multimap<CarrierId, Integer> reverseAospCarrierListPerParentCanonicalId() throws IOException { + + com.android.providers.telephony.CarrierIdProto.CarrierList.Builder aospCarrierList = + com.android.providers.telephony.CarrierIdProto.CarrierList.newBuilder(); + try (InputStream textpb = + CarrierConfigConverterV2.class.getResourceAsStream(RESOURCE_CARRIER_LIST); + BufferedReader textpbReader = new BufferedReader(new InputStreamReader(textpb, UTF_8))) { + TextFormat.getParser().merge(textpbReader, aospCarrierList); + } + Multimap<Integer, CarrierId> res = aospCarrierList.getCarrierIdList().stream() + .filter(cid -> cid.getParentCanonicalId() > 0) + .collect( + flatteningToMultimap( + cid -> cid.getParentCanonicalId(), + cid -> carrierAttributeToCarrierId(cid.getCarrierAttributeList()).stream(), + MultimapBuilder.linkedHashKeys().arrayListValues()::build)); + + return res.entries().stream() + .collect( + toMultimap( + entry -> entry.getValue(), + entry -> entry.getKey(), + MultimapBuilder.linkedHashKeys().arrayListValues()::build)); + } + // Convert `CarrierAttribute`s to `CarrierId`s. // A CarrierAttribute message with fields not supported by CarrierSettings, like preferred_apn, // is ignored. @@ -566,13 +597,19 @@ public final class CarrierConfigConverterV2 { * @return a map, key being the carrier config key, value being a {@link CarrierConfig.Config} * with one of the value set. */ - private static HashMap<String, CarrierConfig.Config> parseCarrierConfigFromVendorXml( + private HashMap<String, CarrierConfig.Config> parseCarrierConfigFromVendorXml( Document xmlDoc, CarrierIdentifier carrier) throws IOException { HashMap<String, CarrierConfig.Config> configMap = new HashMap<>(); for (Element element : getElementsByTagName(xmlDoc, TAG_CARRIER_CONFIG)) { if (carrier != null && !checkFilters(element, carrier)) { continue; } + + Element parent_config = findParentConfigByUniqueRuleId(element); + if (parent_config != null) { + configMap.putAll(parseCarrierConfigToMap(parent_config)); + } + configMap.putAll(parseCarrierConfigToMap(element)); } return configMap; @@ -592,7 +629,8 @@ public final class CarrierConfigConverterV2 { nList = element.getElementsByTagName("boolean"); for (int i = 0; i < nList.getLength(); i++) { Node nNode = nList.item(i); - if (nNode.getNodeType() != Node.ELEMENT_NODE) { + if (nNode.getNodeType() != Node.ELEMENT_NODE || + !nNode.getParentNode().isSameNode(element)) { continue; } Element eElement = (Element) nNode; @@ -604,7 +642,8 @@ public final class CarrierConfigConverterV2 { nList = element.getElementsByTagName("int"); for (int i = 0; i < nList.getLength(); i++) { Node nNode = nList.item(i); - if (nNode.getNodeType() != Node.ELEMENT_NODE) { + if (nNode.getNodeType() != Node.ELEMENT_NODE || + !nNode.getParentNode().isSameNode(element)) { continue; } Element eElement = (Element) nNode; @@ -616,7 +655,8 @@ public final class CarrierConfigConverterV2 { nList = element.getElementsByTagName("long"); for (int i = 0; i < nList.getLength(); i++) { Node nNode = nList.item(i); - if (nNode.getNodeType() != Node.ELEMENT_NODE) { + if (nNode.getNodeType() != Node.ELEMENT_NODE || + !nNode.getParentNode().isSameNode(element)) { continue; } Element eElement = (Element) nNode; @@ -624,11 +664,25 @@ public final class CarrierConfigConverterV2 { long value = Long.parseLong(eElement.getAttribute("value")); configMap.put(key, CarrierConfig.Config.newBuilder().setLongValue(value).build()); } + // double value + nList = element.getElementsByTagName("double"); + for (int i = 0; i < nList.getLength(); i++) { + Node nNode = nList.item(i); + if (nNode.getNodeType() != Node.ELEMENT_NODE || + !nNode.getParentNode().isSameNode(element)) { + continue; + } + Element eElement = (Element) nNode; + String key = eElement.getAttribute("name"); + double value = Double.parseDouble(eElement.getAttribute("value")); + configMap.put(key, CarrierConfig.Config.newBuilder().setDoubleValue(value).build()); + } // text value nList = element.getElementsByTagName("string"); for (int i = 0; i < nList.getLength(); i++) { Node nNode = nList.item(i); - if (nNode.getNodeType() != Node.ELEMENT_NODE) { + if (nNode.getNodeType() != Node.ELEMENT_NODE || + !nNode.getParentNode().isSameNode(element)) { continue; } Element eElement = (Element) nNode; @@ -643,7 +697,8 @@ public final class CarrierConfigConverterV2 { nList = element.getElementsByTagName("string-array"); for (int i = 0; i < nList.getLength(); i++) { Node nNode = nList.item(i); - if (nNode.getNodeType() != Node.ELEMENT_NODE) { + if (nNode.getNodeType() != Node.ELEMENT_NODE || + !nNode.getParentNode().isSameNode(element)) { continue; } Element eElement = (Element) nNode; @@ -662,11 +717,12 @@ public final class CarrierConfigConverterV2 { } configMap.put(key, cccb.setTextArray(cctb.build()).build()); } - // bool array + // int array nList = element.getElementsByTagName("int-array"); for (int i = 0; i < nList.getLength(); i++) { Node nNode = nList.item(i); - if (nNode.getNodeType() != Node.ELEMENT_NODE) { + if (nNode.getNodeType() != Node.ELEMENT_NODE || + !nNode.getParentNode().isSameNode(element)) { continue; } Element eElement = (Element) nNode; @@ -685,6 +741,20 @@ public final class CarrierConfigConverterV2 { } configMap.put(key, cccb.setIntArray(ccib.build()).build()); } + // pbundle_as_map + nList = element.getElementsByTagName("pbundle_as_map"); + for (int i = 0; i < nList.getLength(); i++) { + Node nNode = nList.item(i); + if (nNode.getNodeType() != Node.ELEMENT_NODE || + !nNode.getParentNode().isSameNode(element)) { + continue; + } + Element eElement = (Element) nNode; + String key = eElement.getAttribute("name"); + HashMap<String, CarrierConfig.Config> value = parseCarrierConfigToMap(eElement); + configMap.put(key, CarrierConfig.Config.newBuilder() + .setBundle(toCarrierConfigBuilder(value)).build()); + } return configMap; } @@ -723,6 +793,8 @@ public final class CarrierConfigConverterV2 { break; case "name": // name is used together with cid for readability. ignore for filter. + case "unique_rule_id": + case "following": break; default: System.err.println("Unsupported attribute " + attribute + "=" + value); @@ -838,32 +910,127 @@ public final class CarrierConfigConverterV2 { } private static CarrierIdentifier getCid( - CarrierId carrierId, Multimap<CarrierId, Integer> reverseAospCarrierList) { + CarrierId carrierId, Multimap<CarrierId, Integer> reverseAospCarrierList, + Multimap<CarrierId, Integer> reverseAospCarrierListPerParentCanonicalId) { // Mimic TelephonyManager#getCarrierIdFromMccMnc, which is implemented by // CarrierResolver#getCarrierIdFromMccMnc. CarrierId mccMnc = CarrierId.newBuilder().setMccMnc(carrierId.getMccMnc()).build(); int mccMncCarrierId = reverseAospCarrierList.get(mccMnc).stream().findFirst().orElse(-1); - List<Integer> cids = ImmutableList.copyOf(reverseAospCarrierList.get(carrierId)); + int parentCanonicalId = getParentCanonicalId(carrierId, cids, reverseAospCarrierListPerParentCanonicalId); // No match: use -1 if (cids.isEmpty()) { - return CarrierIdentifier.create(carrierId, -1, -1, mccMncCarrierId); + if (considerParentCanonicalId) { + return CarrierIdentifier.create(carrierId, parentCanonicalId, -1, mccMncCarrierId); + } else { + return CarrierIdentifier.create(carrierId, -1, -1, mccMncCarrierId); + } } // One match: use as both carrierId and specificCarrierId if (cids.size() == 1) { - return CarrierIdentifier.create(carrierId, cids.get(0), cids.get(0), mccMncCarrierId); + if (considerParentCanonicalId) { + return CarrierIdentifier.create(carrierId, parentCanonicalId, cids.get(0), mccMncCarrierId); + } else { + return CarrierIdentifier.create(carrierId, cids.get(0), cids.get(0), mccMncCarrierId); + } } // Two matches: specificCarrierId is always bigger than carrierId if (cids.size() == 2) { - return CarrierIdentifier.create( - carrierId, - Math.min(cids.get(0), cids.get(1)), - Math.max(cids.get(0), cids.get(1)), - mccMncCarrierId); + if (considerParentCanonicalId) { + return CarrierIdentifier.create( + carrierId, + parentCanonicalId, + Math.max(cids.get(0), cids.get(1)), + mccMncCarrierId); + } else { + return CarrierIdentifier.create( + carrierId, + Math.min(cids.get(0), cids.get(1)), + Math.max(cids.get(0), cids.get(1)), + mccMncCarrierId); + } } // Cannot be more than 2 matches. throw new IllegalStateException("More than two cid's found for " + carrierId + ": " + cids); } + private static int getParentCanonicalId( + CarrierId carrierId, + List<Integer> cids, + Multimap<CarrierId, Integer> reverseAospCarrierListPerParentCanonicalId) { + + List<Integer> parentCids = ImmutableList.copyOf(reverseAospCarrierListPerParentCanonicalId.get(carrierId)); + if (cids.isEmpty()) { + if (parentCids.isEmpty()) { + return -1; + } else { + return parentCids.get(0); + } + } else if (cids.size() == 1) { + if (parentCids.isEmpty()) { + return cids.get(0); + } else { + return parentCids.get(0); + } + } else if (cids.size() == 2) { + if (parentCids.isEmpty()) { + return Math.min(cids.get(0), cids.get(1)); + } else { + return parentCids.get(0); + } + } else { + return -1; + } + } private CarrierConfigConverterV2() {} + + // The hash map to store all the configs with attribute "unique_rule_id". + // The config entry with attribute "following" can inherit from the config + // with matching "unique_rule_id". + // Both "unique_rule_id" and "following" attributes can only appear in vendor xml. + private HashMap<String, Element> mUniqueRules = new HashMap<>(); + + private void loadUniqueRulesFromVendorXml(List<Document> vendorXmls) + throws IOException { + for (Document vendorXml : vendorXmls) { + for (Element element : getElementsByTagName(vendorXml, TAG_CARRIER_CONFIG)) { + NamedNodeMap attributes = element.getAttributes(); + boolean uniqueRuleIdSeen = false; + for (int i = 0; i < attributes.getLength(); i++) { + String attribute = attributes.item(i).getNodeName(); + String value = attributes.item(i).getNodeValue(); + switch (attribute) { + case "unique_rule_id": + if (mUniqueRules.containsKey(value)) { + throw new IOException("The carrier_config has duplicated unique_rule_id: " + attributes); + } else if (uniqueRuleIdSeen) { + throw new IOException("The carrier_config has more than 1 unique_rule_id: " + attributes); + } + mUniqueRules.put(value, element); + uniqueRuleIdSeen = true; + break; + default: + break; + } + } + } + } + } + + private Element findParentConfigByUniqueRuleId(Element childElement) { + NamedNodeMap attributes = childElement.getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + String attribute = attributes.item(i).getNodeName(); + String value = attributes.item(i).getNodeValue(); + switch (attribute) { + case "following": + return mUniqueRules.get(value); + //break; + default: + break; + } + } + return null; + } + } diff --git a/proto/carrier_settings.proto b/proto/carrier_settings.proto index 1a8a77f..5a18c24 100644 --- a/proto/carrier_settings.proto +++ b/proto/carrier_settings.proto @@ -182,6 +182,8 @@ message CarrierConfig { bool bool_value = 5; TextArray text_array = 6; IntArray int_array = 7; + CarrierConfig bundle = 8; + double double_value = 9; } } diff --git a/python/update_apn.py b/python/update_apn.py index 0ee32aa..2a74149 100644 --- a/python/update_apn.py +++ b/python/update_apn.py @@ -30,6 +30,7 @@ from google.protobuf import text_format import carrier_list_pb2 import carrier_settings_pb2 +import carrierId_pb2 parser = argparse.ArgumentParser() parser.add_argument( @@ -37,6 +38,10 @@ parser.add_argument( parser.add_argument( '--data_dir', default='./data', help='Folder path for CarrierSettings data') parser.add_argument( + '--support_carrier_id', action='store_true', help='To support using carrier_id in apns.xml') +parser.add_argument( + '--aosp_carrier_list', default='packages/providers/TelephonyProvider/assets/latest_carrier_id/carrier_list.textpb', help='Resource file path to the AOSP carrier list file') +parser.add_argument( '--out_file', default='./tmpapns.textpb', help='Temp APN file') FLAGS = parser.parse_args() @@ -68,13 +73,14 @@ def get_cname(cid, known_carriers): Returns: string for canonical name, like verizon_us or 27402 """ - name = to_string(cid) + return get_known_cname(to_string(cid), known_carriers) + +def get_known_cname(name, known_carriers): if name in known_carriers: return known_carriers[name] else: return name - def get_knowncarriers(files): """Create a mapping from mccmnc and possible mvno data to canonical name. @@ -233,6 +239,99 @@ def gen_apnitem(node): return apn +def is_mccmnc_only_attribute(attribute): + """Check if the given CarrierAttribute only contains mccmnc_tuple + + Args: + attribute: message CarrierAttribute defined in carrierId.proto + + Returns: + True, if the given CarrierAttribute only contains mccmnc_tuple + False, otherwise + """ + for descriptor in attribute.DESCRIPTOR.fields: + if descriptor.name != "mccmnc_tuple": + if len(getattr(attribute, descriptor.name)): + return False + return True + +def process_apnmap_by_mccmnc(apn_node, pb2_carrier_id, known, apn_map): + """Process apn map based on the MCCMNC combination in apns.xml. + + Args: + apn_node: APN node + pb2_carrier_id: carrier id proto from APN node + known: mapping from mccmnc and possible mvno data to canonical name + apn_map: apn map + + Returns: + None by default + """ + apn_carrier_id = apn_node.getAttribute('carrier_id') + if apn_carrier_id != '': + print("Cannot use mccmnc and carrier_id at the same time," + + " carrier_id<" + apn_carrier_id + "> is ignored.") + cname = get_cname(pb2_carrier_id, known) + apn = gen_apnitem(apn_node) + apn_map[cname].append(apn) + +def process_apnmap_by_carrier_id(apn_node, aospCarrierList, known, apn_map): + """Process apn map based on the carrier_id in apns.xml. + + Args: + apn_node: APN node + aospCarrierList: CarrierList from AOSP + known: mapping from mccmnc and possible mvno data to canonical name + apn_map: apn map + + Returns: + None by default + """ + cname_map = dict() + apn_carrier_id = apn_node.getAttribute('carrier_id') + if apn_carrier_id != '': + if apn_carrier_id in cname_map: + for cname in cname_map[apn_carrier_id]: + apn_map[cname].append(gen_apnitem(apn_node)) + else: + # convert cid to mccmnc combination + cnameList = [] + for aosp_carrier_id in aospCarrierList.carrier_id: + aosp_canonical_id = str(aosp_carrier_id.canonical_id) + if aosp_canonical_id == apn_carrier_id: + for attribute in aosp_carrier_id.carrier_attribute: + mcc_mnc_only = is_mccmnc_only_attribute(attribute) + for mcc_mnc in attribute.mccmnc_tuple: + cname = mcc_mnc + # Handle gid1, spn, imsi in the order used by + # CarrierConfigConverterV2#generateCanonicalNameForOthers + gid1_list = attribute.gid1 if len(attribute.gid1) else [""] + for gid1 in gid1_list: + cname_gid1 = cname + ("GID1=" + gid1.upper() if gid1 else "") + + spn_list = attribute.spn if len(attribute.spn) else [""] + for spn in spn_list: + cname_spn = cname_gid1 + ("SPN=" + spn.upper() if spn else "") + + imsi_list = attribute.imsi_prefix_xpattern if\ + len(attribute.imsi_prefix_xpattern) else [""] + for imsi in imsi_list: + cname_imsi = cname_spn + ("IMSI=" + imsi.upper() if imsi else "") + + if cname_imsi == cname and not mcc_mnc_only: + # Ignore fields which cannot be handled for now + continue + + cnameList.append(get_known_cname(cname_imsi, known)) + break # break from aospCarrierList.carrier_id since cid is found + if cnameList: + for cname in cnameList: + apn_map[cname].append(gen_apnitem(apn_node)) + + # cache cnameList to avoid searching again + cname_map[aosp_canonical_id] = cnameList + else: + print("Can't find cname list, carrier_id in APN files might be wrong : " + apn_carrier_id) def main(): known = get_knowncarriers([FLAGS.data_dir + '/' + f for f in CARRIER_LISTS]) @@ -240,11 +339,19 @@ def main(): with open(FLAGS.apn_file, 'r', encoding='utf-8') as apnfile: dom = minidom.parse(apnfile) + with open(FLAGS.aosp_carrier_list, 'r', encoding='utf-8', newline='\n') as f: + aospCarrierList = text_format.Parse(f.read(), carrierId_pb2.CarrierList()) + apn_map = collections.defaultdict(list) for apn_node in dom.getElementsByTagName('apn'): - cname = get_cname(gen_cid(apn_node), known) - apn = gen_apnitem(apn_node) - apn_map[cname].append(apn) + pb2_carrier_id = gen_cid(apn_node) + if pb2_carrier_id.mcc_mnc or not FLAGS.support_carrier_id: + # case 1 : mccmnc + # case 2 : mccmnc+mvno + process_apnmap_by_mccmnc(apn_node, pb2_carrier_id, known, apn_map) + else: + # case 3 : carrier_id + process_apnmap_by_carrier_id(apn_node, aospCarrierList, known, apn_map) mcs = carrier_settings_pb2.MultiCarrierSettings() for c in apn_map: |